Introduction

Welcome to the fourth lesson of the "Broken Access Control" course! In this lesson, we will explore the concept of privilege escalation, a critical aspect of broken access control vulnerabilities.

By understanding how attackers can exploit these vulnerabilities to gain unauthorized access to higher-level privileges, you'll be better equipped to secure your applications. Let's dive in and learn how to prevent privilege escalation! 🚀

Understanding Privilege Escalation

Privilege escalation occurs when an attacker gains elevated access to resources that are normally protected from an application or user. This is a common and severe vulnerability that can give an attacker full control over an application or system.

There are two main types of privilege escalation:

  1. Vertical Privilege Escalation: This is when an attacker gains higher-level privileges. It's like a regular hotel guest getting a master keycard that opens every room.

    • Example: A regular user manipulates a request to change their role to admin.
    • Example: An attacker accesses an admin-only dashboard (e.g., /admin/dashboard) that lacks proper access control checks.
  2. Horizontal Privilege Escalation: This is when an attacker gains access to the resources of another user with the same level of privileges. It's like a hotel guest using their keycard to open the room next door.

    • Example: A user changes the id in a URL like /orders/123 to /orders/124 and successfully views another user's order.
    • Example: An attacker accesses another user's private messages or profile information.

Understanding these concepts is vital for securing web applications against unauthorized access. Let's look at a vulnerable code example to see how these vulnerabilities can manifest in real applications.

Vulnerable Code Example

Let's examine a code snippet that demonstrates a vulnerability allowing vertical privilege escalation. This example shows how a lack of proper validation can lead to unauthorized role changes.

The vulnerability lies in the for loop. It iterates through all key-value pairs in the JSON payload sent by the client and uses setattr to update the user object's attributes directly. This is known as mass assignment. Because there is no filter, an attacker can include sensitive fields like role in their request, and the server will blindly update them.

Exploiting the Vulnerability

To understand the impact of the vulnerability, let's see how it can be exploited. An attacker could use a simple curl request to change their role to admin.

This command sends a request to update the user's profile. The JSON payload includes the role field with the value admin. Without proper validation, the application accepts this change, granting the attacker unauthorized admin privileges. This highlights the importance of securing code against such exploits.

Securing Endpoints with JWT Authentication

The first step to fixing this is to ensure users can only modify their own data. As we saw in the previous lesson, we can use JWT authentication to securely identify the current user.

Instead of accepting a user ID from the URL path (e.g., /users/{id}), which can be easily manipulated, we should create a dedicated endpoint like /users/profile that always acts on the authenticated user. We can extract the user's ID directly from their JWT token using a helper function:

This modification ensures that users can only update their own profiles, as the ID comes from their authenticated token, not the URL. This effectively prevents horizontal privilege escalation. However, we still need to restrict which fields they can update to prevent vertical privilege escalation.

Preventing Mass Assignment with Whitelisting

To prevent a user from changing their own role, we must stop blindly accepting all fields from the request payload. The best practice is to use a whitelist (or "allow list") of fields that a non-admin user is permitted to change.

We can check the user's role. If they are not an admin, we only process the fields present in our allowed_fields set.

You'll notice that we've excluded the password field from our allowed_fields set. This is intentional. Password updates require special handling because they must be hashed before storage, as we learned in the previous lesson. In production applications, password changes should always be handled through a dedicated endpoint that validates the current password and properly hashes the new one. Mixing password updates with general profile updates is a security anti-pattern that can lead to plaintext password storage if the hashing step is forgotten.

In this secure version:

  • We define an allowed_fields set containing fields that are safe for a user to modify.
  • We create a safe_update_data dictionary using a dictionary comprehension that contains only the keys from the payload that are also in our allowed_fields set. This prevents them from submitting and changing sensitive fields like role.
Conclusion and Next Steps

In this lesson, we explored the concept of privilege escalation and how it can be exploited through vulnerabilities in web applications. We examined a vulnerable code example and demonstrated how it can be exploited. By implementing secure coding practices, such as JWT authentication, role-based access control, and proper validation, we can prevent privilege escalation and protect our applications.

As you move on to the practice exercises, apply what you've learned to identify and fix privilege escalation vulnerabilities. This hands-on experience will reinforce your understanding and prepare you for more advanced security challenges. Keep exploring and stay secure! 🔒

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal