If a malicious user gains access to functionality that only system administrators should have access to, there can be dire consequences. This post is about a specific type of vulnerability called broken object level authorization, or BOLA. This happens when an attacker gains access to API methods that should be restricted. In addition to talking about what this is, I'll discuss ways to mitigate this attack in general, and specifically in Java Spring Boot.
Broken Object Level Authorization Defined
Back-end APIs are basically a set of functions that return answers to requests. For instance, if we run an e-commerce shop, API will handle many functions. Some examples include getting the product description, getting the product inventory, setting the product price, adding the product to the shopping cart, checking out, and sending an invoice, among other things. Some of those actions should be accessible to every user who reaches the store, whether it's an application or a website. For example, all users should be able to get product details, get product category details, and view the shipping policy page.
On the other hand, other actions should be strictly performed by specific users only. For instance, shop administrators should be the only ones who can update product inventory or set a product price. Only specific store shoppers should be able to add a specific product to the cart and check out with their order.
If the store developers don't enforce proper permissions on those actions, serious consequences can occur.
For example, a malicious actor will be able to add products to a cart in the name of an existing client. Or they can change the shipping address and pay for them with the existing client's payment method. Moreover, if the malicious user successfully accesses functionality that only the store's administrator should be able to manage, the consequences might be much worse. We call this vulnerability broken object level authorization.
Technical Specifics of a Broken Object Level Authorization Vulnerability
As described above, broken object level authorization is basically a vulnerability that allows an attacker access to restricted data or functionality. Now let's see how it happens in detail. Usually, APIs use URLs of the following structure to access specific resources of items: http://domain.com/api/version/resource/sub-resource/id. In addition, the ID of the resource can appear in the header of the request or in the body instead of the URL. In any case, to access a certain resource, each user generally needs to undergo two steps: authentication and authorization.
Authentication basically means logging in. The system receives a combination of a username and password or an API access token and then validates those credentials against the data that it stores. If users enter the correct credentials, they can log in and do API requests.
However, authentication is not the full story here. It's just the first step. Being authenticated just means that the API "knows who you are." It doesn't mean that you can actually do requests to API endpoints. This stage is authorization. Each user can have different privileges grouped into a "role," and each endpoint can have granular permissions. For instance, an endpoint that accesses a product page will allow all users to view the data, but only the store admin can edit anything. Basically, there should be a check for each API call if the user who has issued it has access to the endpoint and has permission to do the specific action.
A developer can implement authorization in different ways. For instance, we can send the API_token with each request. The API code will check the API_token against the action the user wants to perform and the token's permissions list. Alternatively, we can store the permissions in an encrypted way on the client side. Then it can be sent over to the server with each request.
Breaking Into the API
The specifics of how an attacker can break into an API are application specific.
The general idea, as stated above, is to gain privileges to restricted data or actions. Hijacking the API_TOKEN can be easily done if the API token is sent as part of the URL request: http://domain.com/api/version/resource/sub-resource/id?api_token=randomApiToken1422345. Alternatively, an attacker can do it by copying an encrypted JSON web token from a client machine. However, in most cases, this is just human error when API developers don't properly check the permissions on their end.
The Spring framework is a superb Java framework for creating web applications and enterprise applications. In 2005, Pivotal developed the Spring framework, and it's still very popular today. Ever since Pivotal developed the Spring framework, they have added various modules to the core Spring container. Spring Boot is one of the most commonly used ones, and it is the convention over configuration (CoC) part of the Spring framework. Spring Boot lets you code with very minimal configuration.
Mitigating Broken Object Level Authorization Vulnerability
I'll first discuss how to mitigate this vulnerability in general and then dive into Spring Boot specifics. To mitigate this vulnerability, API developers should first and foremost put authentication and authorization code in place. Without those, any API endpoint is compromised. In addition, proper test cases should cover those mechanisms via unit tests, component tests, and integration tests. Tests should cover at least the most popular and business-critical endpoints. In addition, the tests should cover different use cases. For instance, let's say that a user has entered the wrong credentials. The expected behavior is that no API endpoint can be accessed. The user tries to access an endpoint that they don't have access to. The expected behavior is that access will be denied.
Verify that each user has specific permissions. If you are deploying a more robust user management system that includes user roles, then make sure that a role hierarchy is in place. For example, an administrator can do all guest actions but not vice versa. Likewise, to prevent request forgeries, don't use an API token as a query param, as in this example: http://domain.com/api/version/resource/sub-resource/id?api_token=randomApiToken1422345. Require API users to refresh their credentials periodically. Don't store permission information in an unencrypted browser cookie on the client's side.
Mitigating Broken Object Level Authorization Vulnerability in Spring Boot
Luckily, Spring Boot has Spring Security. This is a robust and built-in way to handle authentication and authorization, thus preventing this vulnerability. Since Spring Security is very robust and has lots of configuration options, we can't cover all of it here. However, it is sufficient to point out that it provides you with BOLA mitigation out of the box. We can use this snippet:
This enables Spring Security in our application automatically. This configuration protects our endpoints by default. And we need to manually set permissions for each endpoint to make it accessible to users. This is a good starting point for developing any new API in Spring Boot. Having said that, users have to take into account that Spring Security can have a steep learning curve. It can also be overkill for their needs. If you are building a small API, then developing authentication and authorization from scratch can be the right way to go.
BOLA is a serious vulnerability. An attacker can get access to restricted information or functionality. OWASP considers it to be the #1 API vulnerability. Broken object level authorization usually occurs due to human error in API implementation. However, despite its serious impact, its mitigation is straightforward (at least strategy wise) through proper authentication and authorization. Spring comes with a module that handles those out of the box, which, in turn, can make mitigating this vulnerability easier for Spring Boot users.
This post was written by Alexander Fridman. Alexander is a veteran in the software industry with over 11 years of experience. He worked his way up the corporate ladder and has held the positions of Senior Software Developer, Team Leader, Software Architect, and CTO. Alexander is experienced in frontend development and DevOps, but he specializes in backend development.