Header Injection with Hmac Signatures
How Header Injection Manifests in Hmac Signatures
Header injection in HMAC signatures occurs when untrusted input is incorporated into HTTP headers without proper validation, creating opportunities for signature bypass or authentication bypass. The vulnerability typically manifests in the signing process itself, where header values are concatenated or serialized before being hashed.
Consider a typical HMAC signing implementation:
const signRequest = (url, method, headers, body) => {
const signingString = [
method,
url,
headers['content-type'],
headers['content-length'],
body || ''
].join('\n');
const hmac = crypto.createHmac('sha256', secret);
hmac.update(signingString);
return hmac.digest('base64');
};
The vulnerability emerges when header values contain newline characters. An attacker can inject additional headers by including '\n' in a header value:
// Malicious header value
headers['content-type'] = 'application/json\nX-Evil-Header: malicious-value';
This creates a signing string that includes the attacker's header, effectively allowing them to control what gets signed without knowing the secret key.
Another common manifestation involves timestamp manipulation. Many HMAC implementations include timestamps in headers:
// Vulnerable timestamp handling
const timestamp = headers['x-timestamp'] || Date.now();
If the timestamp header accepts arbitrary values and isn't properly validated, an attacker can replay old requests or manipulate clock skew calculations.
Header injection also appears in key derivation scenarios. Some systems derive sub-keys from headers:
// Vulnerable key derivation
const deriveKey = (userAgent) => {
return crypto.createHmac('sha256', masterKey)
.update(userAgent)
.digest('base64');
};
Here, a crafted user-agent string could lead to predictable key derivation or collision attacks.
HMAC Signatures-Specific Detection
Detecting header injection in HMAC implementations requires examining both the signing logic and the header processing pipeline. Static analysis tools can identify vulnerable patterns, but runtime detection is crucial for comprehensive coverage.
Key detection patterns include:
- Newline character validation in header values before signing
- Header length restrictions to prevent buffer overflow attacks
- Strict header name validation against a whitelist
- Timestamp validation with acceptable clock skew ranges
- Canonicalization of header ordering and formatting
middleBrick's black-box scanning approach is particularly effective for HMAC signature vulnerabilities because it tests the actual runtime behavior without requiring source code access. The scanner sends requests with crafted header values containing newline characters and observes whether the server accepts them or if the signature verification fails.
For example, middleBrick tests:
// Test for newline injection
const maliciousHeaders = {
'content-type': 'application/json\nX-Injected: test',
'x-custom': 'value\nAnother-Header: injected'
};
The scanner then analyzes the server's response to determine if the injection succeeded. If the server processes the injected headers or if the signature verification behaves unexpectedly, this indicates a vulnerability.
middleBrick also checks for common HMAC implementation flaws:
- Missing or weak timestamp validation
- Inconsistent header ordering in signing vs verification
- Failure to normalize header case sensitivity
- Improper handling of empty or missing headers
The scanner's parallel testing approach evaluates all 12 security checks simultaneously, including authentication bypass attempts that specifically target HMAC implementations.
HMAC Signatures-Specific Remediation
Remediating header injection in HMAC signatures requires a defense-in-depth approach that addresses both the signing process and the header validation pipeline.
Start with strict header validation before any signing occurs:
const validateHeaders = (headers) => {
const allowedHeaders = new Set([
'content-type',
'content-length',
'x-timestamp',
'authorization'
]);
for (const headerName in headers) {
if (!allowedHeaders.has(headerName.toLowerCase())) {
throw new Error(`Disallowed header: ${headerName}`);
}
const value = headers[headerName];
if (typeof value !== 'string' || value.includes('\n') || value.includes('\r')) {
throw new Error(`Header value contains invalid characters: ${headerName}`);
}
}
};
Next, implement canonicalization of the signing string to ensure consistent formatting:
const createCanonicalString = (method, url, headers, body) => {
const sortedHeaders = Object.keys(headers)
.map(key => [key.toLowerCase(), headers[key]])
.sort(([a], [b]) => a.localeCompare(b));
const headerString = sortedHeaders
.map(([key, value]) => `${key}:${value}`)
.join('\n');
return [
method.toUpperCase(),
url,
headerString,
body || ''
].join('\n');
};
For timestamp handling, implement strict validation with acceptable clock skew:
const validateTimestamp = (timestamp, maxSkewSeconds = 300) => {
const now = Date.now();
const skew = Math.abs(now - timestamp);
if (skew > maxSkewSeconds * 1000) {
throw new Error('Timestamp outside acceptable range');
}
};
When deriving keys from headers, use a secure key derivation function instead of direct HMAC:
const deriveSecureKey = (input, salt) => {
return crypto.pbkdf2Sync(
input,
salt,
100000,
32,
'sha256'
);
};
Finally, implement comprehensive logging and monitoring for signature verification failures:
const verifySignature = (request, signature, secret) => {
try {
const signingString = createCanonicalString(
request.method,
request.url,
request.headers,
request.body
);
const hmac = crypto.createHmac('sha256', secret);
hmac.update(signingString);
const computed = hmac.digest('base64');
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(computed))) {
log.warning('Signature mismatch', { remoteAddr: request.ip });
return false;
}
return true;
} catch (error) {
log.error('Signature verification error', { error, remoteAddr: request.ip });
return false;
}
};
These remediation steps, combined with regular middleBrick scanning, provide comprehensive protection against header injection attacks targeting HMAC signatures.