Bleichenbacher Attack with Api Keys
How Bleichenbacher Attack Manifests in API Keys
The Bleichenbacher attack, originally discovered in 1998, exploits PKCS#1 v1.5 padding in RSA encryption to recover plaintext through adaptive chosen-ciphertext attacks. While historically associated with SSL/TLS, this vulnerability manifests in API keys when they're transmitted or stored using vulnerable RSA implementations.
In API key contexts, the attack typically targets RSA-encrypted tokens or credentials sent between services. The attacker intercepts an encrypted API key and sends modified versions to the server, observing whether decryption succeeds or fails. By analyzing these error responses, the attacker gradually recovers the original API key.
// Vulnerable API key transmission pattern
const crypto = require('crypto');
// BAD: Using PKCS#1 v1.5 padding (vulnerable to Bleichenbacher)
const encryptKey = (apiKey, publicKey) => {
const encrypted = crypto.publicEncrypt({
key: publicKey,
padding: crypto.constants.RSA_PKCS1_PADDING, // ⚠️ Vulnerable
oaepHash: 'sha256'
}, Buffer.from(apiKey));
return encrypted.toString('base64');
};
// GOOD: Using OAEP padding (secure)
const encryptKeySecure = (apiKey, publicKey) => {
const encrypted = crypto.publicEncrypt({
key: publicKey,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, // ✅ Secure
oaepHash: 'sha256'
}, Buffer.from(apiKey));
return encrypted.toString('base64');
};
The attack is particularly dangerous in microservices architectures where API keys are exchanged between services using RSA encryption. An attacker on the network can capture encrypted traffic and mount the attack without needing the private key.
Real-world impact: In 2018, researchers demonstrated Bleichenbacher attacks against TLS 1.2 implementations, showing how timing differences in error responses could be exploited. For API keys, the same principle applies—servers that reveal whether padding was correct provide the oracle needed for the attack.
API Keys-Specific Detection
Detecting Bleichenbacher vulnerabilities in API key implementations requires examining both code and runtime behavior. middleBrick's API security scanner specifically tests for this vulnerability through several methods:
Static Analysis: The scanner examines your API's OpenAPI specification and source code for vulnerable RSA padding schemes. It flags any use of PKCS#1 v1.5 padding in API key encryption or signing operations.
// middleBrick scan output for Bleichenbacher vulnerability
{
"severity": "high",
"category": "Encryption",
"finding": "Vulnerable PKCS#1 v1.5 padding detected in API key encryption",
"remediation": "Use RSA_PKCS1_OAEP_PADDING instead of RSA_PKCS1_PADDING",
"impact": "Attacker can recover encrypted API keys through chosen-ciphertext attacks",
"code_sample": "crypto.publicEncrypt({ padding: crypto.constants.RSA_PKCS1_PADDING })"
}
Dynamic Testing: The scanner actively tests API endpoints that handle encrypted API keys by sending modified ciphertexts and analyzing server responses. Consistent timing patterns or error message differences indicate a vulnerable implementation.
Compliance Mapping: Bleichenbacher vulnerabilities map to multiple compliance requirements including OWASP API Top 10 (A1: Broken Object Level Authorization when keys are compromised) and PCI-DSS requirements for strong cryptography.
middleBrick's 12-second scan tests the unauthenticated attack surface, including any endpoints that accept encrypted API keys or tokens. The scanner doesn't require credentials—it tests the exposed API surface as an external attacker would.
Additional detection methods include:
- Network traffic analysis for RSA key exchanges using vulnerable padding
- Code review for deprecated crypto APIs
- Testing for timing side-channels in decryption operations
- Checking for error message leakage that reveals padding validity
API Keys-Specific Remediation
Remediating Bleichenbacher vulnerabilities in API key implementations requires both immediate fixes and architectural changes. Here are specific solutions for common API key scenarios:
1. Update Padding Schemes: The most critical fix is replacing vulnerable PKCS#1 v1.5 padding with secure alternatives.
// BEFORE: Vulnerable implementation
const encryptedKey = crypto.publicEncrypt({
key: publicKey,
padding: crypto.constants.RSA_PKCS1_PADDING, // ⚠️ Vulnerable
oaepHash: 'sha256'
}, Buffer.from(apiKey));
// AFTER: Secure implementation
const encryptedKeySecure = crypto.publicEncrypt({
key: publicKey,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, // ✅ Secure
oaepHash: 'sha256'
}, Buffer.from(apiKey));
2. Implement Constant-Time Decryption: Ensure decryption operations take constant time regardless of input validity.
// Secure decryption with constant-time operations
const decryptKey = (encryptedData, privateKey) => {
try {
const decrypted = crypto.privateDecrypt({
key: privateKey,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: 'sha256'
}, Buffer.from(encryptedData, 'base64'));
// Always perform same operations regardless of result
const isValid = validateApiKey(decrypted.toString());
// Return generic error without timing differences
if (!isValid) {
throw new Error('Invalid API key');
}
return decrypted.toString();
} catch (error) {
// Log error internally but return generic response
console.error('Decryption error:', error.message);
throw new Error('Decryption failed');
}
};
3. Use Modern Key Exchange: Replace RSA key transport with modern key exchange mechanisms like ECDH or use symmetric encryption for API keys.
// Modern approach using ephemeral keys
const generateSharedSecret = (privateKey, publicKey) => {
const ecdh = crypto.createECDH('secp256k1');
ecdh.setPrivateKey(privateKey);
return ecdh.computeSecret(publicKey);
};
// Encrypt API key with shared secret using AES
const encryptApiKey = (apiKey, sharedSecret) => {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(
'aes-256-gcm',
sharedSecret,
iv
);
const encrypted = Buffer.concat([
cipher.update(apiKey),
cipher.final()
]);
return Buffer.concat([
iv,
encrypted,
cipher.getAuthTag()
]).toString('base64');
};
4. Add Rate Limiting and Monitoring: Implement detection for unusual decryption patterns that might indicate an active attack.
// Rate limiting for decryption attempts
const MAX_DECRYPTION_ATTEMPTS = 5;
const RATE_LIMIT_WINDOW = 60000; // 1 minute
const decryptionAttempts = new Map();
const secureDecrypt = (encryptedData, privateKey, clientId) => {
const now = Date.now();
const attempts = decryptionAttempts.get(clientId) || [];
// Remove old attempts
const recentAttempts = attempts.filter(t => now - t < RATE_LIMIT_WINDOW);
if (recentAttempts.length >= MAX_DECRYPTION_ATTEMPTS) {
throw new Error('Rate limit exceeded');
}
decryptionAttempts.set(clientId, [...recentAttempts, now]);
// Perform decryption with constant-time validation
return decryptKey(encryptedData, privateKey);
};
5. Use middleBrick for Continuous Monitoring: After implementing fixes, use middleBrick's continuous monitoring to ensure your API keys remain secure.
# middleBrick CLI for regular scanning
middlebrick scan https://api.example.com --schedule=daily --threshold=80
# GitHub Action for CI/CD integration
- name: Run middleBrick Security Scan
uses: middlebrick/middlebrick-action@v1
with:
url: ${{ secrets.API_URL }}
threshold: 80
fail-on-warn: true