What Is Broken Object Level Authorization? (And How To Fix It)

What Is Broken Object Level Authorization? (And How To Fix It)

Posted in

The OWASP API Security Project is a list of the top ten security risks facing APIs. Managed by the OWASP Foundation, the list showcases some of the critical vulnerabilities across applications and systems on the web. It serves as a guardrail for developers looking to make their systems more secure.

Within this list, one specific vulnerability sits at the number one position — broken object level authorization. Implementing authorization continues to be a pain point for developers across the board, and as such, understanding this vulnerability, seeing some specific examples, and knowing how to prevent it can go a long way toward resolving a critical security issue.

Below, we’ll look at broken object level authorization (BOLA) and define what it is. We’ll look at a theoretical vector and a practical attack example and highlight some methods you can adopt to resolve this critical design error.

What Does it Mean to have Broken Object Level Authorization?

Object-oriented designs allow systems to place limitations on specific objects at a granular level. In an API, these objects can be almost anything – database records, files, you name it. And simply put, broken object level authorization means that the object does not have the proper authorization controls. This is a risk, because if the user can access something they’re not meant to, the system is fundamentally vulnerable.

Broken authorization can be varied and heavily dependent on how the system is designed to work. Perhaps the most common source of this issue is improper validation. When users submit data to an endpoint, it is tempting to simply trust that submission as it is — the reality is, however, that broken submissions can come from both intentional attacks and accidents. If a user submits a malformed request, asking for too much data or access to a resource they should not have, a system built to trust the user will escalate this request improperly, resulting in broken object level authorization. Overly permissive access controls can result in massive exposure of data and can lead to further compromise of the system quite quickly.

Even if developers do apply stringent access controls, however, the protections of the underlying system themselves must also be reviewed. If a user submits a request that is properly validated and denied, that does not mean the attack has stopped in its tracks. APIs, especially those based around microservices, are designed to allow users to combine functions and endpoints to create transformative queries. Unfortunately, if developers do not ensure that the resources these requests touch are properly protected, be it through rate limiting, anonymization, or obfuscation of internal endpoints, combinatory requests can result in an exposure of data or resources that are otherwise protected by object level authorization approaches.

Example Vector

Let’s imagine we have a platform that handles localized payments at an event. This platform utilizes an endpoint to record the orders per vendor, attaching each order to a unique ID to provide actionable reports for sales, revenue, and utilization.

An attacker sniffing the network determines that requests to the endpoint when a sale is made have an ID appended to the request that follows a predictable pattern. Each vendor has an ID that is a mix of the first five letters of their booth name and the number of their booth. For instance, the first booth is a cosmetics vendor named “Starlight Makeup,” and they occupy booth 9. For every sale that is made, a record endpoint is touched with the ID “starl9.”

The attacker uses this pattern and attempts a query against the endpoint. Because the endpoint assumes that anyone on the local network is a vendor, the query allows the attacker access. The attacker then attempts to request the current sales data from the endpoint and finds that no read access control has been implemented. Armed with the knowledge of this pattern, the attacker can exfiltrate all of the data from every single vendor at the location without being detected.

Practical Example

Unfortunately, there are many well-known examples of broken object level authorization. Perhaps the most prominent in North America was the USPS data breach. In 2018, USPS was breached by an attack that exposed 60 million user records due to broken object level authorization. The attack had to do with USPS’s Informed Visibility API, which allows business and bulk mail senders to get near real-time mail tracking data.

Unfortunately, the API was designed so that it provided both the tracking data and the customer data to whom the mail belongs. This made queries contain both the mail data that was intended, the customer data subset that was intended, and all of the rest of the customer data that was not intended. The flaw also did not restrict the requests themselves, allowing anyone to request any user.

While this was all bad enough, the final nail in the coffin was the fact that the API accepted wildcard search parameters, meaning that specific user IDs did not have to be known — wildcard requests could return all of the records for the dataset regardless of the known ID, opening the entire system to breach, resulting in an exposure of 60 million users.

Resolving Broken Object Level Authorization Vulnerabilities

Thankfully, there are several ways that broken object level authorization issues can be prevented.

Standardize Your Authorization System

First and foremost, systems should be developed that are robust and designed around authorization mechanisms that are proven. Adopting open standards for authorization and then enforcing strict rules upon the underlying resources and endpoints can go a long way towards ensuring that issues like those faced by USPS are not present in your system. Additionally, ensuring the mechanisms are in place while also ensuring that there are no loopholes, escalation points, combinatory vectors, and flaws in logic will ensure that your system is truly as secure as possible.

Use Randomized IDs

Secondly, avoiding patterns in unique IDs is vitally important. Many broken object level authorization attacks come from IDs that increment in a known pattern. Using random IDs as opposed to IDs based around user attributes will go a long way towards ensuring that attacks are slowed, if not stopped entirely.

Continuously Audit

Thirdly, review your codebase often against known attack vectors. Many broken object level authorization vectors arise from systems that were at once secure that have since extended and scaled into a situation where they are no longer secure. Consistently review your codebase and think as if you were an attacker. Performing such continuous auditing is a fundamental practice for establishing a secure posture.

Adopt Zero Trust

Finally, adopt a zero trust model. We have discussed zero trust at length before, but the basic concept is simple — trust nothing, verify everything. Blindly trusting that the requester is what they claim to be is a major security fault, even for internal systems. A zero-trust system will require every user to authenticate and prove that they have access to what they request. This basic posture of distrust will routinely ensure that this access has not been escalated, reining in a multitude of attack types, including broken object level authorization.

Conclusion

Broken object level authorization is a well-known issue, so seeing it at the top of vulnerability lists can be disheartening. With some simple approaches and a shift in thinking, broken object level authorization can be mitigated and prevented handily. Securing your API is not just good business sense — it is a fundamental responsibility of any good developer.

What do you think are some of the core reasons that broken object level authorization is still an issue at large? Let us know in the comments below!