Bleichenbacher Attack in Strapi
How Bleichenbacher Attack Manifests in Strapi
The Bleichenbacher attack exploits PKCS#1 v1.5 padding in RSA encryption, allowing attackers to decrypt ciphertexts without the private key. In Strapi, this vulnerability can appear in several critical areas due to improper handling of cryptographic operations.
Strapi's authentication system uses JWT tokens for API authentication, and when JWTs are signed with RSA private keys, the underlying RSA encryption must be implemented correctly. The attack specifically targets the padding validation process during RSA decryption operations.
In Strapi v3 and earlier versions, the JWT verification process could be vulnerable if the underlying crypto library doesn't implement constant-time padding validation. The attack works by sending modified ciphertexts and observing whether the server responds with padding errors or generic decryption failures.
Consider this vulnerable pattern that might appear in custom Strapi middleware:
const crypto = require('crypto');
function vulnerableRSAVerify(token, publicKey) {
const [header, payload, signature] = token.split('.');
const encryptedSignature = Buffer.from(signature, 'base64');
// Vulnerable: timing side-channel through error messages
try {
const decrypted = crypto.publicDecrypt(publicKey, encryptedSignature);
if (decrypted.slice(0, 2).toString('hex') !== '0002') {
throw new Error('Invalid padding');
}
return true;
} catch (err) {
return false; // Timing leak: different response times
}
}
The critical issue is that error messages and response times can leak information about the padding validation process. An attacker can send millions of modified ciphertexts and statistically determine the correct padding through timing analysis.
Strapi's default configuration uses jsonwebtoken library, which properly handles RSA signatures when configured correctly. However, custom implementations or older Strapi versions may be vulnerable to this attack pattern.
Strapi-Specific Detection
Detecting Bleichenbacher vulnerabilities in Strapi requires examining both the configuration and runtime behavior. middleBrick's API security scanner can identify these issues through black-box testing of your Strapi endpoints.
middleBrick tests for Bleichenbacher vulnerabilities by sending modified RSA-encrypted payloads to endpoints that use JWT authentication. The scanner analyzes response timing patterns and error message consistency to identify potential padding oracle vulnerabilities.
Key detection areas in Strapi include:
- Authentication endpoints that use RSA-signed JWT tokens
- Custom middleware that performs RSA operations
- Plugin configurations that handle cryptographic operations
- Third-party integrations that use RSA encryption
middleBrick's scanning process for Strapi includes:
middlebrick scan https://your-strapi-instance.com/api/auth
The scanner tests for timing inconsistencies in error responses and verifies that RSA operations use constant-time implementations. It specifically looks for:
- Variable response times when sending invalid padding
- Different error messages for padding vs decryption failures
- Implementation of PKCS#1 v1.5 instead of OAEP padding
- Custom crypto code that might bypass security libraries
middleBrick's report provides specific findings for Strapi installations, including the exact endpoints and parameters that may be vulnerable to Bleichenbacher attacks.
Strapi-Specific Remediation
Remediating Bleichenbacher vulnerabilities in Strapi requires updating cryptographic implementations and ensuring proper padding validation. Here are Strapi-specific fixes:
First, update your JWT configuration to use secure implementations:
// config/plugins.js
module.exports = ({ env }) => ({
jwt: {
settings: {
algorithms: ['RS256'],
publicKey: env('JWT_PUBLIC_KEY'),
// Ensure constant-time verification
ignoreExpiration: false,
maxAge: '24h'
}
}
});
For custom RSA operations in Strapi plugins, use OAEP padding instead of PKCS#1 v1.5:
const crypto = require('crypto');
function secureRSAEncrypt(publicKey, data) {
return crypto.publicEncrypt({
key: publicKey,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: 'sha256'
}, Buffer.from(data));
}
function secureRSADecrypt(privateKey, encryptedData) {
return crypto.privateDecrypt({
key: privateKey,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: 'sha256'
}, encryptedData);
}
Update your Strapi authentication middleware to use constant-time comparisons:
const crypto = require('crypto');
function constantTimeCompare(val1, val2) {
const buf1 = Buffer.from(val1);
const buf2 = Buffer.from(val2);
return crypto.timingSafeEqual(buf1, buf2);
}
// In your authentication logic
if (!constantTimeCompare(decryptedHeader, expectedHeader)) {
throw new Error('Invalid token');
}
For Strapi v4 and later, ensure you're using the latest dependencies:
{
"dependencies": {
"@strapi/plugin-users-permissions": "^4.0.0",
"jsonwebtoken": "^9.0.0",
"crypto": "^1.0.0"
}
}
middleBrick's continuous monitoring can verify these fixes remain effective as you update Strapi and its dependencies.