HIGH type confusionaspnethmac signatures

Type Confusion in Aspnet with Hmac Signatures

Type Confusion in Aspnet with Hmac Signatures — how this specific combination creates or exposes the vulnerability

Type confusion in ASP.NET when HMAC signatures are handled can occur when the runtime treats data of one object type as another during deserialization or signature comparison. This often arises when the application uses loosely-typed model binding or dynamic objects and then validates an HMAC without enforcing strict type constraints. For example, an attacker may supply JSON that deserializes into different runtime types depending on feature toggles or polymorphic deserialization settings, causing the server to interpret a property as a different type. If the server uses this altered representation to recompute or compare an HMAC, the computed signature may diverge from the expected value in subtle ways, bypassing intended integrity checks.

A concrete scenario: an endpoint accepts a JSON payload with a field that can be either a string or an object. If the application’s deserialization is not explicitly typed (for instance, using JsonConvert.DeserializeObject<object>), the same JSON may deserialize to different .NET types on different requests. The application may then compute an HMAC over the serialized bytes or a subset of the data. Because the serialized form or selected fields differ by runtime type, the HMAC comparison becomes unreliable. This can lead to a situation where a valid HMAC for one type is incorrectly accepted for another type, undermining message integrity and enabling tampering.

When type confusion interacts with HMAC signatures, the risk is not that the HMAC algorithm is broken, but that the way data is prepared for signing or verified is inconsistent. This inconsistency can produce signature verification results that are attacker-manipulable, especially when the application does not enforce a strict schema before signing or verification. In the context of ASP.NET, this may surface in endpoints that bind to dynamic, ExpandoObject, or permissive JsonSerializerOptions that allow polymorphic deserialization. The OWASP API Security Top 10 highlights broken object level authorization and injection risks that can be exacerbated by such type handling issues, and improper HMAC usage can further expose APIs to tampering or privilege escalation when object types are not rigorously controlled.

To detect this during scanning, middleBrick runs checks that examine input validation, property authorization, and unsafe consumption patterns, correlating findings with the API specification and runtime behavior. The tool does not alter or block requests; it reports inconsistencies that may indicate places where type confusion could weaken HMAC-based integrity. Developers should ensure that data structures are explicitly typed, that polymorphic deserialization is either avoided or handled with strict type discriminators, and that HMAC is computed over a canonical, deterministic representation of the expected type before any comparison.

Hmac Signatures-Specific Remediation in Aspnet — concrete code fixes

Remediation focuses on deterministic serialization, strict typing, and constant-time comparison. Always define explicit DTO classes and avoid binding to object or dynamic for inputs that participate in HMAC verification. Use the same serialization settings (e.g., property naming policy, default values, and ignored fields) for both signing and verification. Compute the HMAC over the exact byte sequence that will be recomputed during verification, and avoid including fields that may change type or presence between requests.

Example using ASP.NET Core with a concrete DTO and HMAC validation:

using System.Security.Cryptography;
using System.Text;
using System.Text.Json;

public class OrderDto
{
    public string OrderId { get; set; }
    public decimal Amount { get; set; }
    public string Currency { get; set; }
}

public static class HmacUtil
{
    private static readonly byte[] Key = Encoding.UTF8.GetBytes("REPLACE_WITH_STRONG_KEY_FROM_CONFIGURATION");

    public static string ComputeHmac(string payload)
    {
        using var hmac = new HMACSHA256(Key);
        byte[] hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(payload));
        return Convert.ToBase64String(hash);
    }

    public static bool VerifyHmac(string payload, string receivedSignature, out string computedSignature)
    {
        computedSignature = ComputeHmac(payload);
        // Use a constant-time comparison to avoid timing attacks
        return CryptographicOperations.FixedTimeEquals(
            Encoding.UTF8.GetBytes(computedSignature),
            Encoding.UTF8.GetBytes(receivedSignature));
    }
}

// In a controller:
[HttpPost("order")]
public IActionResult CreateOrder([FromBody] OrderDto order)
{
    var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
    string canonical = JsonSerializer.Serialize(order, options);
    string signature = HmacUtil.ComputeHmac(canonical);

    // Assume the client sent the signature in a header "X-API-Signature"
    string received = Request.Headers["X-API-Signature"];
    if (HmacUtil.VerifyHmac(canonical, received, out string computed))
    {
        // Proceed only if signatures match
        return Ok(new { Order = order, SignatureVerified = true });
    }
    return Unauthorized(new { Error = "Invalid signature", Computed = computed });
}

Key points in the example:

  • Use a strongly typed DTO (OrderDto) instead of dynamic or object.
  • Serialize with explicit options to ensure a canonical form; avoid default formatting differences that change the byte representation.
  • Compute and verify HMAC over the same serialized payload; do not include mutable headers or query strings unless they are also part of the signed payload in a controlled way.
  • Use a constant-time comparison such as CryptographicOperations.FixedTimeEquals to prevent timing-based signature comparison attacks.
  • Store the HMAC key securely (e.g., using configuration and protecting access) and rotate it according to your security policy.

If you must handle polymorphic data, include a strict type discriminator and enforce type-specific deserialization paths rather than allowing the runtime to decide types arbitrarily. This reduces the chance that the same JSON produces different .NET types and therefore different serialized bytes when recomputed for HMAC verification.

Related CWEs: inputValidation

CWE IDNameSeverity
CWE-20Improper Input Validation HIGH
CWE-22Path Traversal HIGH
CWE-74Injection CRITICAL
CWE-77Command Injection CRITICAL
CWE-78OS Command Injection CRITICAL
CWE-79Cross-site Scripting (XSS) HIGH
CWE-89SQL Injection CRITICAL
CWE-90LDAP Injection HIGH
CWE-91XML Injection HIGH
CWE-94Code Injection CRITICAL

Frequently Asked Questions

How can I ensure my HMAC verification is not affected by polymorphic deserialization in ASP.NET?
Define explicit DTO classes and avoid deserializing to object or dynamic. Use strict type annotations and consistent JsonSerializerOptions so that the same JSON always produces the same .NET type and canonical serialization before HMAC computation.
Is it safe to include all request headers in the HMAC payload in ASP.NET?
Including headers can introduce variability (e.g., ordering, metadata) that complicates deterministic signing. Sign only the canonical body and critical metadata you control; if headers must be included, serialize them in a deterministic order as part of the payload.