Http Request Smuggling in Aspnet with Hmac Signatures
Http Request Smuggling in Aspnet with Hmac Signatures
HTTP request smuggling arises when an ASP.NET application processes requests differently between a front-end proxy (or load balancer) and the ASP.NET runtime, and the use of HMAC signatures does not prevent this mismatch. The front-end may parse requests one way (e.g., favoring the first Content-Length or Transfer-Encoding header) while ASP.NET’s pipeline parses them another, allowing a crafted request to smuggle an additional request through to the backend. This becomes an HMAC-specific concern when the proxy validates or strips the signature before changing how it forwards the request body, or when the signature only covers a subset of headers/body that the runtime then reinterprets.
Consider a scenario where the proxy verifies an HMAC in a custom header (e.g., X-API-Signature) covering the request body and some headers, but does not include the Transfer-Encoding header in the signed payload. An attacker can send a request with both Transfer-Encoding: chunked and Content-Length: 0; the proxy validates the HMAC (which ignores Transfer-Encoding), removes or ignores it, and forwards the body with Content-Length semantics. ASP.NET then parses the request according to its own rules, potentially allowing a second request to be interpreted as part of the same connection. The HMAC did not protect against the presence of conflicting framing headers, enabling request smuggling (e.g., CVE-2021-41773-style attacks on parsers that differ in interpretation).
In ASP.NET Core, the default JSON and form readers consume the request body stream once; if a prior parser has already partially consumed it due to smuggling, model binding can fail, behave unexpectedly, or expose data meant for another request. For APIs using HMAC to ensure integrity, the risk is not that the signature is broken, but that the signature scope is too narrow or the proxy normalizes headers in a way that creates a parsing discrepancy between layers. Attack patterns include smuggling via mismatched handling of Transfer-Encoding and Content-Length, where the proxy’s stripping or reordering of headers invalidates the original parsing assumptions without invalidating the HMAC.
To detect this during scanning, middleBrick runs unauthenticated checks that include both general request smuggling probes and HMAC-specific tests, such as sending requests with conflicting framing headers while preserving a valid signature. The tool examines whether ASP.NET’s runtime interpretation diverges from the proxy’s interpretation and whether the signature scope covers the headers that influence parsing. Findings are reported with severity and remediation guidance, helping teams understand if their HMAC strategy inadvertently masks smuggling vectors.
Hmac Signatures-Specific Remediation in Aspnet
Remediation focuses on ensuring the HMAC covers all headers and body segments that influence parsing, and on normalizing or rejecting requests with conflicting framing before they reach ASP.NET. Below are concrete code examples for an ASP.NET Core middleware that validates HMAC and rejects requests with ambiguous Transfer-Encoding and Content-Length combinations.
First, define a helper to compute and verify the HMAC over a canonical set of headers and the request body. This example uses HMAC-SHA256 and expects the signature in X-API-Signature. It also checks that no conflicting framing headers are present.
using System.Security.Cryptography;
using System.Text;
using Microsoft.AspNetCore.Http;
public static class HmacValidation
{
private const string SignatureHeader = "X-API-Signature";
private static readonly byte[] Key = Encoding.UTF8.GetBytes("REPLACE_WITH_STRONG_KEY_BASE64_OR_CONFIG");
public static bool TryValidateRequest(HttpRequest request, out string errorMessage)
{
// Reject requests with both Transfer-Encoding and Content-Length to prevent smuggling
if (request.Headers.ContainsKey("Transfer-Encoding") && request.Headers.ContainsKey("Content-Length"))
{
errorMessage = "Conflicting Transfer-Encoding and Content-Length headers.";
return false;
}
if (!request.Headers.TryGetValue(SignatureHeader, out var receivedSignature))
{
errorMessage = "Missing signature header.";
return false;
}
// Build canonical payload: selected headers + body
var bodyStream = new MemoryStream();
request.Body.CopyTo(bodyStream);
var body = bodyStream.ToArray();
var headersToSign = new[] { "content-type", "content-length" };
var sb = new StringBuilder();
foreach (var h in headersToSign)
{
if (request.Headers.TryGetValue(h, out var val))
sb.Append($"{h.ToLower()}:{val}\n");
}
sb.Append("body:").Append(Convert.ToBase64String(body));
using var hmac = new HMACSHA256(Key);
var computed = hmac.ComputeHash(Encoding.UTF8.GetBytes(sb.ToString()));
var expected = Convert.ToBase64String(computed);
if (!CryptographicOperations.FixedTimeEquals(Convert.FromBase64String(receivedSignature), computed))
{
errorMessage = "Invalid signature.";
return false;
}
errorMessage = string.Empty;
return true;
}
}
Use this middleware early in the pipeline to ensure invalid requests are rejected before model binding. In Program.cs, add:
app.Use(async (context, next) =>
{
if (!HmacValidation.TryValidateRequest(context.Request, out var error))
{
context.Response.StatusCode = 400;
await context.Response.WriteAsync($"Bad Request: {error}");
return;
}
await next();
});
Additionally, configure Kestrel and any reverse proxy to use consistent parsing rules. For example, prefer the first Content-Length and drop Transfer-Encoding if both are present, or normalize chunked bodies before signature verification. Ensure the set of headers included in the HMAC encompasses those that affect how the body is parsed (e.g., Content-Type, Content-Length). middleBrick’s scans can help verify that your HMAC scope and header normalization prevent smuggling; the dashboard and CLI provide findings and remediation guidance tailored to your framework version.
For continuous protection, the Pro plan enables ongoing monitoring and configurable scans so that future changes to headers or signing logic are flagged. The GitHub Action can enforce a minimum score threshold in CI/CD, while the MCP Server allows you to run checks directly from AI coding assistants during development.