I got really into studying API security recently. While working on the first draft of my book, my technical editor, Aaron Guzman, pointed out that my book on web security needed an API chapter to be complete.
And he has a great point. As modern applications become more complex, they are increasingly built using APIs. And more and more so, APIs have the ability to execute important actions or communicate sensitive information. This makes API bugs a widespread source of security breaches and data leaks. That means it’s worth understanding APIs, the vulnerabilities that manifest in them, and how to defend against these vulnerabilities.
You’ve probably heard of the OWASP top ten or the top ten vulnerabilities that threaten web applications. OWASP also periodically selects a list of top ten vulnerabilities that threaten APIs, called the OWASP API top ten. The current API top ten are Broken Object Level Authorization, Broken User Authentication, Excessive Data Exposure, Lack of Resources & Rate Limiting, Broken Function Level Authorization, Mass Assignment, Security Misconfiguration, Injection, Improper Assets Management, and Insufficient Logging & Monitoring.
Many of these vulnerabilities affect application components besides APIs as well, but they tend to manifest themselves in APIs. Today, let’s talk about the OWASP API #1 vulnerability, Broken Object Level Authorization.
APIs often expose object identifiers used to access resources. And when access control is not properly implemented on these endpoints, attackers can view or operate on resources that they should not have access to. This vulnerability affects all types of API architectures, including SOAP, REST, and GraphQL.
Let's take a look at an example! Say that an API allows users to retrieve details about their payment methods based on their user ID:
Here, if the application does not require additional proof of identity in the API call and simply returns the requested data to anyone, the application exposes the sensitive information to attackers. Attackers can either guess, leak, or brute force a victim’s ID and steal their payment information via the API endpoint.
Often, applications allow users to access data objects based on an object ID instead of their user IDs. Example.com also has an API endpoint that allows users to retrieve the contents of their private messages. Messages are referenced using numeric IDs:
If the server does not implement access control on this endpoint, attackers can brute force these numeric IDs and retrieve other users’ messages!
These were instances of Broken Object Level Authorization. There is no identity check in place before users access individual data objects. The server was not verifying if you were the legitimate user. It simply returned the information, as you asked.
Besides endpoints that read data objects, these issues can also affect API endpoints that update, delete or create data entries too. For instance, a common issue in GraphQL implementations is that the API allows unauthorized users to edit data by switching out IDs in mutation requests.
The impact of Broken Object-Level Access Control depends on the data object exposed. If a critical object like users’ PII and credentials are exposed, the bug could cause a data breach or the compromise of the application.
This vulnerability could be exploited even more aggressively: attackers could write a script to query all user IDs and scrape data automatically. If this vulnerability was to happen on an online shopping site, attackers might be able to harvest millions of bank accounts, credit card numbers, and addresses. If this vulnerability was found on a banking site, attackers could leak everyone’s credit information and tax forms!
And if a write-based Broken Object-Level Access Control happens on critical functionalities such as password reset, password change, and account recovery, attackers can often pivot these vulnerabilities to take over user or admin accounts.
The ideal way to prevent this issue is to infer the API user’s identity from an access token or another form of secret. Then, implement access control on all sensitive API endpoints that require some privilege. Also, remember that every API endpoint and request method needs to be audited and properly protected. For instance, I often see API implementations where simply changing to a different request method will bypass controls.
If that is not possible, reference data objects with random and unpredictable values instead of simple numeric IDs. However, simply using a random ID cannot be considered well-rounded protection since IDs can be leaked or stolen. Let’s say that this API endpoint is not restricted by access control:
Even though it’s hard to guess the IDs used to reference messages, attackers might be able to steal or leak these IDs. These IDs might also be made available to browser extensions and browsing histories.
Preventing Broken Object-Level Authorization should be your top priority as a developer. But even APIs with proper object-level authorization can be vulnerable to attacks. Implementing proper authentication mechanisms for an API service could also be tricky. Next time, let’s look at the OWASP API top ten #2, Broken User Authentication, and how authentication issues manifest in APIs in the form of weak tokens, long-living tokens, and token leaks. Up next, API tokens and why they are sometimes a huge nightmare. See ya!
What other security concepts do you want to learn about? I’d love to know. Feel free to connect on Twitter @vickieli7.
Want to learn more about application security? Take our free OWASP top ten courses here: https://www.shiftleft.io/learn/.