Missing Authentication with Hmac Signatures
How Missing Authentication Manifests in Hmac Signatures
Missing authentication in HMAC signatures occurs when APIs fail to verify the cryptographic integrity of incoming requests. In HMAC-based authentication, the server expects a signature header containing a hash generated from the request body and a shared secret key. When this verification step is bypassed or improperly implemented, attackers can forge requests without detection.
A common manifestation is when developers comment out or remove the signature verification code during debugging, then forget to restore it. For example:
// INSECURE: Signature verification disabled
const isValidSignature = true; // Should be: verifyHmacSignature(request, secret)Another pattern is conditional verification that never triggers. Consider this flawed implementation:
function verifyRequest(req) {
if (req.headers['x-api-key']) {
// Only verifies if API key exists, but what if it's missing?
return verifyHmacSignature(req, process.env.SHARED_SECRET);
}
return true; // INSECURE: Missing API key means no verification
}Timing attacks can also expose HMAC vulnerabilities. If the verification function returns early on signature mismatch without constant-time comparison, attackers can brute-force secrets by measuring response times. This is especially dangerous in HMAC implementations that use simple string comparison:
// VULNERABLE: Non-constant time comparison
function insecureCompare(sig1, sig2) {
if (sig1.length !== sig2.length) return false;
let result = 0;
for (let i = 0; i < sig1.length; i++) {
result |= sig1.charCodeAt(i) ^ sig2.charCodeAt(i);
// No constant-time execution - leaks timing information
}
return result === 0;
}Missing authentication also appears when HMAC signatures are generated but never validated on the server side. A typical scenario involves frontend code that signs requests for analytics or logging, but the backend never checks these signatures:
// Frontend signs requests
const signedRequest = signWithHmac(requestBody, userSecret);
fetch('/api/endpoint', { headers: { 'x-signature': signedRequest } });Without server-side verification, this provides zero security benefit while creating a false sense of protection.
Hmac Signatures-Specific Detection
Detecting missing HMAC authentication requires both static analysis and runtime testing. Static analysis tools can identify code patterns where HMAC verification is absent or bypassed. Look for these red flags:
// Pattern 1: Missing verification call
app.post('/api/data', (req, res) => {
// HMAC signature should be verified here
processData(req.body); // Vulnerable - no auth check
Runtime detection involves sending requests with manipulated signatures to observe server behavior. A properly implemented HMAC system should reject requests with:
- Missing signature headers
- Modified request bodies without updated signatures
- Invalid signature formats
- Expired timestamp parameters (if using time-based HMAC)
middleBrick's black-box scanning approach tests these scenarios automatically. The scanner sends crafted requests to your API endpoints and analyzes responses for authentication bypasses. For HMAC endpoints, it tests:
| Test Case | Expected Behavior | Security Risk |
|---|---|---|
| Missing signature header | 401 Unauthorized | Critical - authentication bypass |
| Modified payload | 401 Unauthorized | Critical - integrity bypass |
| Invalid signature format | 401 Unauthorized | High - format validation missing |
| Replay attack | Rejected (if implemented) | Medium - replay protection missing |
The scanner also analyzes your OpenAPI specification to identify endpoints that should use HMAC authentication but may have missing implementation. It cross-references documented security requirements with actual runtime behavior.
For HMAC-specific detection, middleBrick examines the signature algorithm and key management practices. Weak algorithms like MD5 or SHA-1 indicate potential vulnerabilities, even if the implementation appears complete. The scanner flags endpoints using deprecated cryptographic primitives.
Hmac Signatures-Specific Remediation
Remediating missing HMAC authentication requires implementing proper verification with constant-time comparison and secure key management. Here's a secure HMAC implementation using Node.js and crypto:
const crypto = require('crypto');
function verifyHmacSignature(req, secret) {
const signature = req.headers['x-signature'];
if (!signature) return false;
const hmac = crypto.createHmac('sha256', secret);
hmac.update(JSON.stringify(req.body));
const computedSignature = hmac.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(computedSignature)
}
function secureHandler(req, res, next) {
const isValid = verifyHmacSignature(req, process.env.SHARED_SECRET);
return res.status(401).json({ error: 'Invalid signature' });
}
next();
}For time-based HMAC to prevent replay attacks, include a timestamp in the signature:
function generateHmacWithTimestamp(body, secret) {
const timestamp = Date.now();
const payload = { body, timestamp };
const hmac = crypto.createHmac('sha256', secret);
hmac.update(JSON.stringify(payload));
return `${hmac.digest('hex')}.${timestamp}`;
}
function verifyHmacWithTimestamp(req, secret, maxAgeMs = 300000) {
const [signature, timestamp] = req.headers['x-signature'].split('.');
const age = Date.now() - parseInt(timestamp);
if (age > maxAgeMs) return false; // Expired
const hmac = crypto.createHmac('sha256', secret);
hmac.update(JSON.stringify({ body: req.body, timestamp }));
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(hmac.digest('hex'))
);
}Key management is critical for HMAC security. Never hardcode secrets in your application code:
// INSECURE - hardcoded secret
const secret = 'my-super-secret-key-123'; // Exposed in source controlInstead, use environment variables or secret management services:
// SECURE - environment variable
const secret = process.env.HMAC_SHARED_SECRET;
if (!secret) {
throw new Error('HMAC secret not configured');
}For distributed systems, consider using a key rotation strategy. Store multiple valid keys and support backward compatibility during rotation:
const activeKeys = [
process.env.CURRENT_HMAC_SECRET,
process.env.PREVIOUS_HMAC_SECRET // For ongoing requests
Finally, implement comprehensive logging for HMAC failures to detect potential attacks:
function logHmacFailure(req, reason) {
console.warn(`HMAC verification failed: ${reason}`, {
ip: req.ip,
endpoint: req.path,
timestamp: new Date().toISOString(),
userAgent: req.headers['user-agent']
});
}Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |