HIGH bola idoraspnethmac signatures

Bola Idor in Aspnet with Hmac Signatures

Bola Idor in Aspnet with Hmac Signatures — how this specific combination creates or exposes the vulnerability

Broken Object Level Authorization (BOLA) in ASP.NET APIs often occurs when an endpoint uses predictable identifiers (e.g., /users/{id}) and enforces access control only at the route or action level, without verifying ownership or authorization context. When HMAC signatures are introduced as a integrity mechanism—typically to sign request payloads or selected headers—the vulnerability can shift or persist depending on how the signature is validated and bound to the resource.

Consider an ASP.NET Core endpoint that accepts an object identifier and an HMAC signature in headers, such as X-API-Key and X-Request-Signature. If the server validates the HMAC to ensure request integrity but does not associate the signature with the specific resource or the authenticated principal, an attacker can reuse a valid signature for another user’s resource. For example, User A has a valid HMAC-signed request for /api/users/123. If User B’s identifier is predictable (e.g., /api/users/124), and the server only verifies the HMAC format and not whether the signed data includes or binds the user ID, User B may be able to tamper with the ID in the request path while presenting User A’s valid HMAC. Because the signature does not cover the full authorization context (including the object ID or tenant), BOLA occurs: the server authorizes based on signature validity rather than on whether the requesting subject is allowed to access that specific object.

This pattern is common when teams treat HMAC as a lightweight integrity check and assume it implicitly prevents tampering with identifiers. In ASP.NET, if the HMAC is computed over a subset of the request—such as the body or selected headers—and the route parameter or query parameter is excluded from the signed payload, attackers can modify the unprotected parameter and the server will still accept the request. The vulnerability is exacerbated when the HMAC key is static across users or sessions, or when the server skips per-request nonce/timestamp checks, enabling replay across different resource IDs. Identifiers that are not opaque or unguessable (e.g., sequential integers) further lower the bar for BOLA. Even with HMAC integrity, without binding the signature to the resource identifier and enforcing strict ownership checks at the data layer, ASP.NET APIs remain susceptible to BOLA.

To illustrate, an ASP.NET endpoint that only validates the HMAC and then directly uses the id route value without cross-checking permissions is vulnerable:

// Vulnerable pattern: signature validated, but id is not bound to the signature or user context
[HttpGet("/api/users/{id}")]
public async Task<IActionResult> GetUser(int id, [FromHeader] string xRequestSignature)
{
    if (!ModelState.IsValid) return BadRequest();
    if (!_hmacValidator.Validate(Request.Headers, id, out var error)) return Unauthorized();

    var user = await _userRepository.GetByIdAsync(id); // BOLA: no ownership check
    if (user == null) return NotFound();
    return Ok(user);
}

In this scenario, _hmacValidator.Validate may confirm the signature integrity, but it does not ensure the signed context includes the id or that the current principal is allowed to view that id. An attacker can iterate over numeric IDs, supply a valid HMAC (perhaps captured from a legitimate request), and access unauthorized resources.

Hmac Signatures-Specific Remediation in Aspnet — concrete code fixes

To mitigate BOLA when using HMAC signatures in ASP.NET, bind the signature to the full request context—including the resource identifier—and enforce ownership checks before data access. The HMAC should be computed over a canonical string that includes the HTTP method, path, selected headers, and the resource identifier (or a stable representation of it). Validate the signature early, then confirm that the requesting subject has explicit rights to the referenced object.

Below is a concrete, secure ASP.NET Core example that signs and verifies a canonical string containing the method, path, and ID, and then verifies ownership before returning the resource:

// Secure HMAC handling with resource binding and ownership check
public class HmacValidator
{
    private readonly byte[] _key;
    private readonly IUserResolver _userResolver;

    public HmacValidator(IConfiguration config, IUserResolver userResolver)
    {
        _key = Convert.FromBase64String(config["Hmac:Key"]);
        _userResolver = userResolver;
    }

    public bool Validate(HttpRequest request, string resourceId, out string error)
    {
        error = null;
        if (!request.Headers.TryGetValue("X-Request-Signature", out var signatureHeader))
        {
            error = "Missing signature";
            return false;
        }

        string canonical = $"{request.Method}:{request.Path}:{resourceId}";
        using var hmac = new HMACSHA256(_key);
        var computed = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(canonical)));
        if (!CryptographicOperations.FixedLengthEquals(Convert.FromBase64String(signatureHeader), Convert.FromBase64String(computed)))
        {
            error = "Invalid signature";
            return false;
        }
        return true;
    }
}

[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
    private readonly HmacValidator _hmacValidator;
    private readonly IUserRepository _userRepository;

    public UsersController(HmacValidator hmacValidator, IUserRepository userRepository)
    {
        _hmacValidator = hmacValidator;
        _userRepository = userRepository;
    }

    [HttpGet("{id}")]
    public async Task<IActionResult> Get(int id)
    {
        if (!_hmacValidator.Validate(Request, id.ToString(), out var error))
        {
            return Unauthorized();
        }

        // Enforce ownership/authorization: ensure the requesting user can access this id
        var currentUserId = _userResolver.GetCurrentUserId(User);
        if (currentUserId != id)
        {
            return Forbid();
        }

        var user = await _userRepository.GetByIdAsync(id);
        if (user == null) return NotFound();
        return Ok(user);
    }
}

Key elements in the remediation:

  • The canonical string includes the HTTP method, path, and the resource identifier (id.ToString()), ensuring the signature is unique per resource.
  • Signature validation uses a fixed-time comparison to avoid timing attacks.
  • Ownership is verified independently of signature validation, ensuring the subject matches the resource before data access.
  • The HMAC key is injected securely and not hard-coded; in production it should be stored in a secure configuration/secrets provider.

For broader protection across controllers, consider an action filter in ASP.NET that performs canonical construction, signature validation, and ownership checks before action execution. This keeps the binding logic consistent and reduces the risk of missing BOLA checks in individual endpoints.

Related CWEs: bolaAuthorization

CWE IDNameSeverity
CWE-250Execution with Unnecessary Privileges HIGH
CWE-639Insecure Direct Object Reference CRITICAL
CWE-732Incorrect Permission Assignment HIGH

Frequently Asked Questions

Why does including the resource ID in the HMAC canonical string prevent BOLA?
Including the resource ID ensures the signature is unique to that object. An attacker cannot reuse a valid signature for another ID because the canonical string differs, causing validation to fail.
Is HMAC alone enough to protect against BOLA in ASP.NET APIs?
No. HMAC provides integrity, but you must also enforce ownership/authorization checks and bind the signature to the full request context, including the resource identifier and the authenticated principal.