Hello Everyone,

I hope you are doing well. Today in this article, We will review one of OWASP vulnerabilities, A01:2021-Broken Access Control, and its remedy and best code practice to enhance the security of web applications.

Explanation

Broken Access Control is one of the most common web application vulnerabilities listed in the OWASP Top 10. It occurs when a user can perform actions and access resources that they are not authorized to access, often due to insufficient enforcement of access control policies.

Access control involves restricting access to resources based on user permissions. Broken access control happens when an attacker can bypass these restrictions due to implementation flaws, misconfigurations, or design issues. This can allow attackers to view or modify unauthorized data, perform unauthorized actions, and generally escalate their privileges within an application.

Types of Broken Access Control

1. Horizontal Privilege Escalation

Vulnerable Code

[HttpGet]
[Route("api/document/get")]
public IActionResult GetDocument(int documentId)
{
    var document = _dbContext.Documents.FirstOrDefault(doc => doc.DocumentId == documentId);
    
    if (document != null)
    {
        return Ok(document);
    }
    
    return NotFound();
}

In the above code, any authenticated user can access any document just by knowing its document ID.

Secure Code

[HttpGet]
[Route("api/document/get")]
public IActionResult GetDocument(int documentId)
{
    var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
    
    var document = _dbContext.Documents.FirstOrDefault(doc => 
        doc.DocumentId == documentId && doc.OwnerId == userId);

    if (document != null)
    {
        return Ok(document);
    }
    
    return NotFound();
}

Now, users can only access documents they own.

2. Vertical Privilege Escalation

Vulnerable Code

[HttpPost]
[Route("api/user/promote")]
public IActionResult PromoteUser(int userId)
{
    var user = _dbContext.Users.Find(userId);
    
    if (user != null)
    {
        user.Role = "Admin";
        _dbContext.SaveChanges();
        return Ok();
    }
    
    return NotFound();
}

Any authenticated user can promote any user to an admin role.

Secure Code

[HttpPost]
[Route("api/user/promote")]
[Authorize(Roles = "Admin")]
public IActionResult PromoteUser(int userId)
{
    var user = _dbContext.Users.Find(userId);
    
    if (user != null)
    {
        user.Role = "Admin";
        _dbContext.SaveChanges();
        return Ok();
    }
    
    return NotFound();
}

The [Authorize(Roles = "Admin")] ensures that only users with an "Admin" role can promote others to admin status.

3. Bypassing Access Control Checks

Vulnerable Code

[HttpGet]
[Route("api/settings/get")]
public IActionResult GetSettings()
{
    // Suppose sensitive settings should be admin-only
    return Ok(_dbContext.Settings.First());
}

Secure Code

[HttpGet]
[Route("api/settings/get")]
[Authorize(Roles = "Admin")]
public IActionResult GetSettings()
{
    return Ok(_dbContext.Settings.First());
}

The use of [Authorize(Roles = "Admin")] prevents non-admin users from accessing sensitive settings.

4. Insecure Direct Object References (IDOR)

Vulnerable Code

[HttpGet]
[Route("api/profile/view")]
public IActionResult ViewProfile(int userId)
{
    var profile = _dbContext.UserProfiles.FirstOrDefault(p => p.UserId == userId);
    
    if (profile != null)
    {
        return Ok(profile);
    }
    
    return NotFound();
}

Users can view any user's profile just by changing the user ID.

Secure Code

[HttpGet]
[Route("api/profile/view")]
public IActionResult ViewProfile(int userId)
{
    var authenticatedUserId = int.Parse(User.Identity.GetUserId());
    
    if (userId != authenticatedUserId)
    {
        return Unauthorized();
    }
    
    var profile = _dbContext.UserProfiles.FirstOrDefault(p => p.UserId == userId);
    
    if (profile != null)
    {
        return Ok(profile);
    }
    
    return NotFound();
}

Now, users are restricted to only viewing their profile.

5. Missing Function Level Access Control

Vulnerable Code

[HttpGet]
[Route("api/data/export")]
public IActionResult ExportData()
{
    // Export sensitive data
    return Ok(_dbContext.SensitiveData.ToList());
}

There's no control over who can export sensitive data.

Secure Code

[HttpGet]
[Route("api/data/export")]
[Authorize(Roles = "Admin")]
public IActionResult ExportData()
{
    return Ok(_dbContext.SensitiveData.ToList());
}

Only admins can now export sensitive data.

Each of these examples illustrates the importance of proper authorization in web applications to protect resources from unauthorized access. Always ensure that both the backend and frontend enforce access controls correctly. Regular audits and security tests are also vital to maintain a secure application.

Remedies and Code Practices to Prevent Broken Access Control

Conclusion

Broken access control is a critical and prevalent security vulnerability that exposes sensitive data and functionality to unauthorized users, leading to significant security risks. Proper mitigation involves implementing robust access control mechanisms such as RBAC (Role-Based Access Control) and ABAC (Attribute-Based Access Control), adopting secure coding practices, and ensuring consistent enforcement across the application. Regular security audits, user education, and compliance with legal and regulatory standards are essential to prevent and manage these vulnerabilities effectively. Proactive prevention and response strategies are crucial for maintaining the security and trustworthiness of software applications.