The highest API Security Risk: Broken Authorization
Authorization is difficult to implement and test because it’s multi-dimensional and requires a deeper understanding of our APIs. In this article, I’ll explain how authorization is broken and what we can do to protect our systems.
If we look at the OWASP Top 10 API Security Risks, Broken Authorization occupies three positions. Why is that?
Authorization is difficult to implement and test because it’s multi-dimensional and requires a deeper understanding of our APIs. In this article, I’ll explain how authorization is broken and what we can do to protect our systems.
Let’s get started!
You can also watch or listen the content of this article on YouTube
What is Authorization?
In the context of APIs, authorization is the process of deciding whether a user is allowed to perform a particular request. It works in tandem with authentication.
While Authentication focuses on identifying WHO or WHAT is invoking our API, Authorization defines WHAT ACTIONS or WHAT RESOURCES the identified user can access.
Authorization can be broken at three levels:
- Function
- Object
- Object Property
Broken Function Level Authorization (BFLA)
Authorization is broken at the function level when users can access functions that they have no permission to use.
Imagine we are building a multi-tenant system where each organization has only one administrator authorized to add or remove users. User management APIs must be inaccessible to standard users.
We typically mitigate this risk with two simple steps:
- We deny all requests by default.
- We implement a form of Role-Based Access Control (RBAC) where each function must declare which roles are authorized.
This is enough to remove any possibility of having functions without any authorization control. However, it is not enough to prevent misconfigurations, especially if authorization is implemented in code or through annotated business functions. We’ll get back to this later in the article.
Broken Object Level Authorization (BOLA)
Authorization is broken at the object level when users can access resources without the necessary rights (typically ownership or granted permission).
In our scenario, while an administrator can access the user management function, we must prevent her from managing another organization just by changing an ID in the URL or Request Body.
Unfortunately, this vulnerability is extremely common and easy to discover with automated tools. Most importantly, Role-Base Access Control is 100% ineffective in this scenario.
Broken Object Property Level Authorization (BOPLA)
Similarly, RBAC is ineffective against Broken Object Property Level Authorization (BOPLA) where users can read or modify object properties without the necessary rights.
Imagine we have an API that is pulling data straight from a database table. If we add a sensitive property after releasing the API, it will be exposed as is to the end user.
If also have an endpoint that allows the user to update the entire object at once, we can mistakenly give her the ability of modifying this property.
So, how do we deal with BOLA and BOPLA?
Mitigating BOPLA
Let me start with the easy stuff.
We can fix object property level authorization by introducing layers in our application. We never create a straight pipe from the DB to our API which means we need to use different classes to represent an object at the API and DB level so that we can safely strip out sensitive data.
I also recommend working with API specifications that define the minimum amount of data we need for each endpoint. You can use these specifications to auto-generate server stubs. If you never did this, I have a 20-minute tutorial that can guide you in this process.
Mitigating BOLA
Many development teams opt for the easiest option which is to implement ownership or relationship checks right within the business logic. The main problem with this approach is visibility. We are fully reliant on code reviews and ad-hoc tests to spot bugs or misconfigurations. Obviously, we all make mistakes and what typically happens is that vulnerabilities are introduced silently and discovered only when a malicious actor, or hopefully our security team, manages to exploit it.
The proper approach would be to implement a fine-grained access control system like the Attribute-Based Access Control (ABAC) where policies are defined in terms of the user and object attributes or environment conditions.
Let me be honest. Implementing such a system is a huge undertaking. My suggestion is for you to research and find a ready-made solution that fits your stack and needs. I’ll give you a couple of examples.
If you work with Kubernetes, you should be familiar with the Open Policy Agent. This solution can be used to secure HTTP APIs as well.
If you secure your APIs with OAuth and OpenID Connect, you might have heard about Keycloak which is an open-source identity and access management solution that supports fine-grained authorization policies; ABAC included.
If you use a graph database, you might also consider ReBAC which stands for Relationship Based Access Control. In this system, we can create a hierarchy of named relationships between nodes of different types. In our scenario, this approach would allow us to verify if a given user administers the target organization.
There’s a ton of documentation I could share with you. I included everything on there references section at the end of this article!
Automated Security Testing is Key
The last thing I want to mention is the importance of automated testing. OWASP proposes a very interesting approach centered around the concept of a matrix pivot file.
This is a file that is both human and program readable. This would allow any type of user, even a non-programmer, to define which policies the system should enforce. We could use the same file to enforce such policies and generate integration tests that verify that authorization is working as expected.
Conclusion
Let’s sum it up. What we learnt today is that our systems should always deny access by default.
Then, we need to introduce a form of fine-grained access control. RBAC is discouraged because it doesn’t protect us from broken object level and object property level authorization. ABAC and ReBAC are better options.
As we mentioned for authentication in a previous article, this is complicated stuff so we should favor ready-made solutions that implement a standard. Which one is best depends on your stack and the problem you are solving. You’ll need to invest some time in research.
Last but not least, we must share this article so that everyone can learn something new 🙂
YouTube Video
References
Top 10 API Security Risks, Open Worldwide Application Security Project (OWASP), https://owasp.org/API-Security/editions/2023/en/0x11-t10/
Authorization Cheat Sheet, OWASP, https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html
Authorization Testing Automation Cheat Sheet, OWASP, https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Testing_Automation_Cheat_Sheet.html
Guide to Attribute Based Access Control (ABAC) Definition and Consideration, National Institute of Standards and Technology, https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-162.pdf
Role-Based Access Control, Ferraiolo and Kuhn, NIST, https://csrc.nist.gov/files/pubs/conference/1992/10/13/rolebased-access-controls/final/docs/ferraiolo-kuhn-92.pdf
Relationship-Based Access Control (ReBAC), https://en.wikipedia.org/wiki/Relationship-based_access_control
HTTP APIs, Open Policy Agent, https://www.openpolicyagent.org/docs/latest/http-api-authorization/
Authorization Services, Keycloak, https://www.keycloak.org/docs/latest/authorization_services/index.html
Use Cases: Identity and Access Management, Neo4j, https://neo4j.com/use-cases/identity-and-access-management/