Phishing Api Keys with Hmac Signatures
Hmac Signatures-Specific Remediation
Fixing HMAC signature vulnerabilities requires architectural changes to how signatures are constructed and validated. Here are HMAC-specific remediation patterns:
Secure Signature Construction
Remove URLs from HMAC signatures and use relative paths instead:
const createSecureHmacSignature = (path, method, body, apiKey, secret) => {
const timestamp = Date.now();
const nonce = crypto.randomBytes(16).toString('hex');
// Use relative path, not full URL
const stringToSign = `${method.toUpperCase()}
${path}
${timestamp}
${nonce}
${body}`;
const hmac = crypto.createHmac('sha256', secret);
const signature = hmac.update(stringToSign).digest('hex');
return { signature, timestamp, nonce };
};
Tenant-Aware Signatures
For multi-tenant systems, include tenant identifiers:
const createTenantAwareSignature = (tenantId, path, method, body, apiKey, secret) => {
const timestamp = Date.now();
const nonce = crypto.randomBytes(16).toString('hex');
const stringToSign = `${tenantId}
${method.toUpperCase()}
${path}
${timestamp}
${nonce}
${body}`;
const hmac = crypto.createHmac('sha256', secret);
const signature = hmac.update(stringToSign).digest('hex');
return { signature, timestamp, nonce, tenantId };
};
Strict Timestamp Validation
Validate timestamps with minimal windows:
const validateHmacRequest = (request, secret) => {
const { signature, timestamp, nonce, tenantId } = request.headers;
const currentTimestamp = Date.now();
// Reject requests older than 300 seconds (5 minutes)
if (currentTimestamp - parseInt(timestamp) > 300000) {
throw new Error('Signature expired');
}
// Check for clock skew (allow 30 seconds)
if (Math.abs(currentTimestamp - parseInt(timestamp)) > 30000) {
throw new Error('Invalid timestamp');
}
// Verify nonce hasn't been used recently
if (nonceCache.has(nonce)) {
throw new Error('Nonce already used');
}
nonceCache.set(nonce, currentTimestamp);
// Validate signature
const expectedSignature = createSecureHmacSignature(
request.path,
request.method,
request.body,
tenantId,
secret
);
if (expectedSignature !== signature) {
throw new Error('Invalid signature');
}
return true;
};
API Key Rotation Security
Implement secure key rotation without exposing current keys:
// Never expose current key during rotation
const rotateApiKey = async (userId) => {
const newSecret = crypto.randomBytes(32).toString('hex');
const newKey = generateApiKey();
// Create new key in disabled state
await db.keys.create({
userId,
key: newKey,
secret: newSecret,
status: 'pending'
});
// Send secure notification (not the key itself)
await sendRotationNotification(userId, newKey);
return { success: true };
};
GitHub Action Integration
Add HMAC security checks to your CI/CD pipeline:
name: API Security Scan
on: [push, pull_request]
jobs:
hmac-security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run middleBrick HMAC Scan
run: |
npm install -g middlebrick
middlebrick scan https://api.example.com --test=hmac-signature-construction --fail-on-high-severity
env:
MIDDLEBRICK_API_KEY: ${{ secrets.MIDDLEBRICK_API_KEY }}
Continuous Monitoring
Pro customers can set up continuous HMAC signature monitoring:
middlebrick monitor --target=https://api.example.com \
--test=hmac-signature-construction \
--alert=slack \
--schedule=daily \
--threshold=high
This monitors your HMAC implementation daily and alerts your team if new vulnerabilities are detected, helping prevent phishing attacks before they impact production systems.
Frequently Asked Questions
How can I tell if my HMAC signatures are vulnerable to phishing attacks?
middlebrick scan https://your-api.com --test=hmac-signature-construction. The scanner will identify URL-based signatures and other phishing vulnerabilities with specific remediation guidance.What's the difference between URL-based and path-based HMAC signatures?
https://api.example.com/v1/users) in the signature string, while path-based signatures use only the relative path (/v1/users). URL-based signatures are vulnerable to phishing because attackers can capture signed requests and forward them to the real API. Path-based signatures prevent this by ensuring the signature is only valid for the intended service path, not the specific host.