Broken Object Level Authorization is the number one in OWASP’s API security top 10.
APIs tend to expose endpoints that handle object identifiers, creating a wide attack surface of Object Level Access Control issues. Object level authorization checks should be considered in every function that accesses a data source using an ID from the user.
What is Authorization?
Decide if an action can be taken.
- Can Alice view document #123?
- Can Alice view document #123 at 16:30 on Tuesday, 11 June, 2024?
- Can Bob edit document #123 in China?
- Can Bob edit document #123 in China, when authenticated with MFA?
- Can a manager create document #456
We can always identify the following:
- Subject, the user or thing trying to take an action
- Type & identifier
- E.g.
user:Alice,application:123
- E.g.
- Or properties of the subject
- E.g.
manager
- E.g.
- Type & identifier
- Action, the thing the subject is trying to do
- E.g.
view,edit
- E.g.
- Resource, the target of the action
- Type & identifier
- E.g.
document:#123
- Context, any additional information that can influence the decision.
- E.g. time, location, authentication method.
Additionally we often want to search based on the authorization decisions. A search is essentially a decision with one or more free variables.
- Which documents can Alice view?
- Who can view document 123?
- What actions can Alice perform on document 123 on Tuesday, June 11, 2024?
Access control models
Access control models can be separated by their specificity.
Coarse-grained access control models
Role-based access control (RBAC), is the most common access control model. A subject is assigned to a role and depending on their role the application decides whether to allow access.
Coarse grained access control models such as RBAC are easy to implement.
It might look like they are easy to manage but in practice group, entitlements and roles become a mess.
Fine-grained access context models
Often this is implemented by mapping specific actions on resources to entitlements (arbitrary strings) and combining those in a role and assigning those to a group of subjects.
Relationship-based access control (ReBAC) looks at the relation of resources and subjects. Essentially it looks at the graph of resources and subjects to decides whether an action is allowed.
From: https://docs.aserto.com/docs/authorization-basics/authorization-models/rebac
Attribute-based access control (ABAC), compares attributes assigned to a subject and resource to decide if an action is allowed.
Policy-based access control (PBAC), the most generic model. A policy can be any evaluation of any computer program. Often specific domain specific languages are used to describe the policy.
Hybrid models
Coarse-grained and fine-grained can be combined. For example an API gateway or application proxy can check if a user is allowed to access a service using RBAC but the service can use a more fine-grained model such as ReBAC to check if specific actions are allowed on a resource.
This approach can improve performance and provide better (mutli-layered) security.
Google’s Zanzibar
Determining whether online users are authorized to access digital objects is central to preserving privacy. This paper presents the design, implementation, and deployment of Zanzibar, a global system for storing and evaluating access control lists. Zanzibar provides a uniform data model and configuration language for expressing a wide range of access control policies from hundreds of client services at Google, including Calendar, Cloud, Drive, Maps, Photos, and YouTube. Its authorization decisions respect causal ordering of user actions and thus provide external consistency amid changes to access control lists and object contents. Zanzibar scales to trillions of access control lists and millions of authorization requests per second to support services used by billions of people. It has maintained 95th-percentile latency of less than 10 milliseconds and availability of greater than 99.999% over 3 years of production use.
https://research.google/pubs/zanzibar-googles-consistent-global-authorization-system/
Authorization Policies
These describe the rules. From Nist’s guide to ABAC:
Natural Language Policy (NLP): Statements governing management and access of enterprise objects. NLPs are human expressions that can be translated to machine-enforceable access control policies.
Digital Policy (DP): Access control rules that compile directly into machine executable codes or signals. Subject/object attributes, operations, and environment conditions are the fundamental elements of DP, the building blocks of DP rules, which are enforced by an access control mechanism.
Metapolicy (MP): A policy about policies, or policy for managing policies, such as assignment of priorities and resolution of conflicts between DPs or other MPs.
Digital policies are the real software implementation of the policy. These are often described using A DCL XACML, ALFA, Rego, Oso Polar.
A policy evaluation engine takes the authorization policy, and the authorization request and outputs a decision.
Digital Policy example with Rego
Rego is currently the most popular and open language for to define policies, it was developed for the OPA policy engine and is based on the datalog programming language.
Rego is a declerative programming language, made for writing authorization policies.
The following is an example from the Rego playground.
Policy:
package app.abac
default allow := false
allow if user_is_owner
allow if {
user_is_employee
action_is_read
}
allow if {
user_is_employee
user_is_senior
action_is_update
}
allow if {
user_is_customer
action_is_read
not pet_is_adopted
}
user_is_owner if data.user_attributes[input.user].title == "owner"
user_is_employee if data.user_attributes[input.user].title == "employee"
user_is_customer if data.user_attributes[input.user].title == "customer"
user_is_senior if data.user_attributes[input.user].tenure > 8
action_is_read if input.action == "read"
action_is_update if input.action == "update"
pet_is_adopted if data.pet_attributes[input.resource].adopted == true
Data:
{
"user_attributes": {
"alice": {
"tenure": 20,
"title": "owner"
}
},
"pet_attributes": {
"dog123": {
"adopted": true,
"age": 2,
"breed": "terrier",
"name": "toto"
}
}
}
Input:
{
"user": "alice",
"action": "read",
"resource": "dog123"
}
Output:
{
"action_is_read": true,
"allow": true,
"pet_is_adopted": true,
"user_is_owner": true,
"user_is_senior": true
}
Externalized Authorization Architecture
Often the authorization is implemented in the application itself, either hard-coded or trough configurations. But this approach has shortcomings in large, distributed and dynamic systems.
- Policy (interpretation) consistency
- Reuse of implementations
- Policy administration (version control, deployments)
- More difficult to improve performance
For these reasons it is often decided to externalize authorization out of the application.
The simplest approach to externalize authorization is to centralize it in one system. But there are other patterns possible, more on that later.
Defined in XACML and Nist’s guide to ABAC
By Axiomatics - Axiomatics, CC BY 3.0,
https://commons.wikimedia.org/w/index.php?curid=48397652
XACML Dataflow Diagram, image from OASIS spec.
Policy Decision point components
The PDP is shown as one component in the XACML architecture but we can distinguish multiple subcomponents.
Policy Engine is the component responsible for actually evaluating the policy and making a decision.
PDP Interface or API implements how the PEP can send queries to th PDP. Often based upon HTTP and JSON but gRCP. Every PDP implementation uses a different kind of (often proprietary API). But there is a process ongoing by the OpenID foundation to standerize an interface called AuthZEN.
The data plane is responsible for gathering data form the relevant PIP’s. E.g. user & resource attributes. The data plane can also concern itself with caching and structuring the data in a performant data structure such as a graph for performant policy evaluation.
The data plane can exist completely separate from the PDP (any databse or API can be used). But many implementations choose to tightly couple the PDP and PIP for optimal performance.
A policy control plane is required to distribute updates to policies the PDP’s as soon as they are changed. The control plane is the glue between the PAP and PDP. The control plane can also provide information about the configuration of the data plane, such as the location of the PIP’s.
Fancy Archtiectural patterns
OPAL Architecture, from https://docs.opal.ac/overview/architecture/
- Fully centralized service
- Per-tenant
- Per application
- As a library
- Sidecar container
Policy administration (PAP)
Many solutions provide powerful interfaces to manage policies.
Policy creation interface. The digital policy can be written as computer program using any text editor or IDE. But many implementations provide interfaces to make it easy to use for less technical people.
Version control is essential for policy management. Often software VCS such as git ore often used because most operations are already using it. But sometimes authorization services implement their own version control, tightly coupled with the ui of the PAP.
Policy distribution trough the control plane, just like any program the authorization policies require some form of continous deployent, depending on the chosen architecture this can become very complex, requiring deployment to multiple PDP’s without having downtime.
Testing should also be considered, the digital policy is a computer program like any other and there should exist ‘unit’ test to ensure that the policies (and any for changes) behave as expected. Issues in a policy can have huge consequences for the security of the system.
AuthZEN
The OpenID foudnation has identified the need for a standardized interface for authorization, similar to their OpenID connect standard for authentication.
https://openid.github.io/authzen/
AuthZEN is essentially an API specification standardizing the contract between PDP and PEP. It contains two API’s.
- Access Evaluation(s) API
- Search API
Access Evaluation API
Modified example from the AuthZEN draft.
The access evaluation API returns the decision as a boolean, but can also provide some context.
An alternative endpoint is also defined that can evaluate multiple decisions in one request.
Request:
POST /access/v1/evaluation HTTP/1.1
Host: pdp.example.com
Content-Type: application/json
Authorization: Bearer <myoauthtoken>
X-Request-ID: bfe9eb29-ab87-4ca3-be83-a1d5d8305716
{
"subject": {
"type": "user",
"id": "alice@example.com"
},
"resource": {
"type": "document",
"id": "1"
},
"action": {
"name": "edit"
},
"context": {
"time": "1985-10-26T01:22-07:00"
}
}
Response:
HTTP/1.1 OK
Content-Type: application/json
X-Request-ID: bfe9eb29-ab87-4ca3-be83-a1d5d8305716
{
"decision": false,
"context": {
"reason": "Subject is a viewer of the resource"
}
}
Search API
Example form the draft.
The search API can search for subjects, actions and resources.
It also specifies pagination which is which is essential for scalability.
Request:
POST /access/v1/search/resource HTTP/1.1
Host: pdp.example.com
Content-Type: application/json
Authorization: Bearer <myoauthtoken>
X-Request-ID: bfe9eb29-ab87-4ca3-be83-a1d5d8305716
{
"subject": {
"type": "user",
"id": "alice@example.com"
},
"action": {
"name": "can_read"
},
"resource": {
"type": "account"
}
}
Response:
HTTP/1.1 OK
Content-Type: application/json
X-Request-ID: bfe9eb29-ab87-4ca3-be83-a1d5d8305716
{
"page": {
"next_token": "a3M9NDU2O3N6PTI="
},
"results": [
{
"type": "account",
"id": "123"
},
{
"type": "account",
"id": "456"
}
]
}
OAuth Rich Authorization Requests
There also exists an extension to famout OAuth authorization framework to implement FGA.
Ideal for when user interaction (permission) is required before allowing a service to take an action. Or for cross-domain use cases.
From RFC 9396: OAuth 2.0 Rich Authorization Requests:
This specification introduces a new parameter authorization_details that allows clients to specify their fine-grained authorization requirements using the expressiveness of JSON data structures.
For example, an authorization request for a credit transfer (designated as “payment initiation” in several open banking initiatives) can be represented using a JSON object like this:
{
"type": "payment_initiation",
"locations": [
"https://example.com/payments"
],
"instructedAmount": {
"currency": "EUR",
"amount": "123.50"
},
"creditorName": "Merchant A",
"creditorAccount": {
"bic":"ABCIDEFFXXX",
"iban": "DE02100100109307118603"
},
"remittanceInformationUnstructured": "Ref Number Merchant"
}
From RFC 9396: Example of an Authorization Request for a Credit Transfer
The new enemy problem
Audit logs
An advantage is centralizing the authorization is that it also become easier to centralize the decision logs. These are very useful for auditing.
Projects and products
Open source with commercial offering
All most all (production ready) open source implementations of FGA are backed by a commercial company providing a product based upon the open-source project.
Open source / Commercial product.
- OPA / Styra enterprise OPA & DAS
- OPAL / Permit.io
- Aserto / Topaz
- spiceDB / AuhtZed
- OpenFGA / Auth0 (Okta) FGA
- Casbin / Casdoor
Proprietary
Several companies also sell fully closed source authorization services.
- Oso Security
- Ping Authorize
- AWS Cedar
- Axiomatics
- Permify
- Cerbos
Sources & further reading
- https://owasp.org/API-Security/editions/2023/en/0xa1-broken-object-level-authorization/
- https://idpro.org/the-state-of-the-union-of-authorization/
- https://www.permit.io/blog/what-is-fine-grained-authorization-fga
- https://openid.net/wg/authzen/
- https://openid.github.io/authzen/
- https://www.feldera.com/blog/fine-grained-authorization
- https://docs.aserto.com/docs/authorization-basics
- https://datatracker.ietf.org/doc/html/rfc9396