Rate Limiting Bypass with Hmac Signatures
How Rate Limiting Bypass Manifests in Hmac Signatures
Rate limiting bypass in HMAC signatures typically occurs through manipulation of timestamp tolerances and signature replay attacks. HMAC-based authentication systems often implement sliding window tolerances for timestamps to account for clock skew between client and server. Attackers exploit this by sending requests with timestamps that fall within the acceptable window but are strategically spaced to avoid triggering rate limits.
A common bypass pattern involves the following sequence:
1. Request A: timestamp = now - 30s (within 60s tolerance window)
2. Request B: timestamp = now - 25s (still within window)
3. Request C: timestamp = now - 20s (still within window)
4. Request D: timestamp = now - 15s (still within window)
5. Request E: timestamp = now - 10s (still within window)
Each request appears unique to the rate limiter due to different timestamps, yet the attacker can flood the system while staying within the tolerance window. The HMAC signature itself remains valid because the timestamp is part of the signed payload, but the rate limiting mechanism fails to aggregate these logically related requests.
Another sophisticated bypass involves manipulating the nonce or request ID included in HMAC signatures. If the nonce validation is weak or predictable, attackers can reuse nonces across multiple requests while varying other parameters to bypass both replay protection and rate limiting:
// Predictable nonce generation (vulnerable)
const nonce = Date.now().toString(36) + Math.random().toString(36).slice(2);
// Attacker can predict or reproduce nonces
const predictableNonce = Math.floor(Date.now() / 1000).toString(36);
Time-based HMAC signature implementations are particularly vulnerable when they don't properly correlate requests across the timestamp tolerance window. A server configured with a 300-second tolerance window might process requests spanning several minutes without recognizing they're part of a coordinated attack:
// Vulnerable implementation
const MAX_TIMESTAMP_DRIFT = 300; // seconds
const now = Date.now() / 1000;
const timestamp = parseInt(signatureParts[1]);
if (Math.abs(now - timestamp) > MAX_TIMESTAMP_DRIFT) {
return invalid();
}
The core issue is that rate limiting operates on request metadata (IP, user ID, API key) while HMAC validation operates on the signature itself. When these systems don't communicate, attackers can exploit the gap. A single API key might be used to send hundreds of requests with carefully crafted timestamps, each appearing legitimate to the HMAC validator but collectively overwhelming the backend service.
HMAC Signatures-Specific Detection
Detecting rate limiting bypass in HMAC signatures requires analyzing both the signature validation logic and the rate limiting implementation. The most effective detection approach involves monitoring for unusual timestamp distributions in incoming requests. Legitimate traffic typically shows timestamps clustered around the current time, while bypass attempts show patterns of requests spanning the entire tolerance window.
Security scanners like middleBrick can detect this vulnerability by:
- Analyzing the timestamp tolerance window configuration
- Testing requests with timestamps at the boundaries of acceptable ranges
- Observing whether rate limits are consistently enforced across the window
- Checking for predictable nonce generation patterns
- Verifying that request correlation occurs across the tolerance window
- Testing for signature replay within the tolerance window
Here's how a security scan might test for this vulnerability:
// Test script for HMAC rate limiting bypass
async function testRateLimitBypass(baseUrl, apiKey) {
const requests = [];
const tolerance = 300; // seconds
const now = Date.now() / 1000;
// Create requests spanning the tolerance window
for (let i = 0; i < 10; i++) {
const timestamp = now - (tolerance - (i * 30));
const nonce = generatePredictableNonce(i);
const signature = createHmacSignature(apiKey, timestamp, nonce);
requests.push({
url: `${baseUrl}/api/endpoint`,
headers: {
'X-Timestamp': timestamp,
'X-Nonce': nonce,
'Authorization': `HMAC ${signature}`
}
});
}
const responses = await Promise.all(requests.map(req => fetch(req.url, { headers: req.headers })));
const successfulResponses = responses.filter(r => r.status < 400);
return successfulResponses.length === requests.length; // Bypass successful if all pass
}
Log analysis provides another detection vector. Look for these patterns in server logs:
| Pattern | Indicates |
|---|---|
| Multiple requests with timestamps spanning entire tolerance window | Potential bypass attempt |
| Requests with sequential nonces but varied timestamps | Nonce manipulation |
| Same API key producing requests across wide timestamp ranges | Rate limit evasion |
| High request volume with valid signatures but suspicious timing | Coordinated attack |
middleBrick's scanning engine specifically tests for these patterns by submitting requests with manipulated timestamps and nonces, then analyzing whether the server properly correlates and rate limits them. The scanner checks if the HMAC implementation properly validates that requests within the tolerance window are treated as related for rate limiting purposes.
HMAC Signatures-Specific Remediation
Remediating HMAC signature rate limiting bypass requires architectural changes to how requests are correlated and rate limited. The most effective approach is implementing a unified request validation pipeline that considers both HMAC signature validity and rate limiting context before processing any request.
First, implement strict timestamp validation with minimal tolerance windows:
// Strict timestamp validation
const MAX_TIMESTAMP_DRIFT = 60; // seconds (reduced from typical 300+)
const now = Date.now() / 1000;
const timestamp = parseInt(signatureParts[1]);
if (Math.abs(now - timestamp) > MAX_TIMESTAMP_DRIFT) {
return { valid: false, reason: 'timestamp expired' };
}
Second, implement nonce validation that prevents reuse within the tolerance window:
const NONCE_STORE = new Map(); // In-memory store for active nonces
function validateNonce(nonce, timestamp) {
const tolerance = 300; // seconds
const now = Date.now() / 1000;
// Check if nonce was used within tolerance window
if (NONCE_STORE.has(nonce)) {
const lastUsed = NONCE_STORE.get(nonce);
if (Math.abs(now - lastUsed) < tolerance) {
return false; // Nonce reuse detected
}
}
// Update nonce timestamp
NONCE_STORE.set(nonce, now);
return true;
}
Third, implement request correlation that aggregates related requests for rate limiting:
const RATE_LIMITER = new Map(); // Store rate limits by key
function checkRateLimit(apiKey, userId, endpoint) {
const key = `${apiKey}:${userId}:${endpoint}`;
const window = 60; // seconds
}
Fourth, implement a unified validation pipeline that combines all checks:
async function validateAndProcessRequest(request) {
const { timestamp, nonce, apiKey, userId, endpoint } = request.headers;
// Step 1: Validate timestamp
// Step 2: Validate nonce
// Step 3: Check rate limit
// Step 4: Validate HMAC signature
// Step 5: Process request
}
Finally, implement comprehensive logging and monitoring to detect bypass attempts:
// Enhanced logging for security monitoring
function logRequestSecurity(request, outcome) {
const logEntry = {
timestamp: Date.now(),
apiKey: request.headers.apiKey,
userId: request.headers.userId,
// Store in security log
// Trigger alerts for suspicious patterns
}
These remediation steps create a defense-in-depth approach where timestamp manipulation, nonce reuse, and rate limiting bypass become significantly more difficult. The key is ensuring all validation steps work together rather than in isolation, preventing attackers from exploiting the gaps between different security mechanisms.
Related CWEs: resourceConsumption
| CWE ID | Name | Severity |
|---|---|---|
| CWE-400 | Uncontrolled Resource Consumption | HIGH |
| CWE-770 | Allocation of Resources Without Limits | MEDIUM |
| CWE-799 | Improper Control of Interaction Frequency | MEDIUM |
| CWE-835 | Infinite Loop | HIGH |
| CWE-1050 | Excessive Platform Resource Consumption | MEDIUM |