HIGH bleichenbacher attackexpressjavascript

Bleichenbacher Attack in Express (Javascript)

Javascript-Specific Remediation in Express

To mitigate Bleichenbacher vulnerabilities in Express.js applications, developers must eliminate padding oracles by ensuring RSA decryption operations fail indistinguishably for all invalid inputs. This requires using constant-time error handling and avoiding any feedback that distinguishes padding errors from other failures.

The following Express middleware demonstrates secure RSA decryption using PKCS#1 v1.5 padding with constant-time error handling:

const crypto = require('crypto');

function secureRsaDecrypt(privateKeyPem) {
  const privateKey = crypto.createPrivateKey(privateKeyPem);
  
  return function(req, res, next) {
    const token = req.headers['x-auth-token'];
    if (!token) {
      return res.status(401).send('Authentication required');
    }
    
    try {
      const buffer = Buffer.from(token, 'base64');
      // Use PKCS#1 v1.5 padding - but handle all errors identically
      const decrypted = crypto.privateDecrypt({
        key: privateKey,
        padding: crypto.constants.RSA_PKCS1_PADDING
      }, buffer);
      
      // Validate decrypted content (e.g., check structure, timestamp)
      const payload = decrypted.toString('utf8');
      if (!isValidPayload(payload)) {
        // Same error response for invalid padding OR invalid payload
        return res.status(401).send('Invalid token');
      }
      
      req.auth = { payload };
      next();
    } catch (err) {
      // CRITICAL: All errors return identical response
      // No distinction between padding errors, base64 errors, etc.
      res.status(401).send('Invalid token');
    }
  };
}

function isValidPayload(payload) {
  // Example: payload must be JSON with exp > now
  try {
    const data = JSON.parse(payload);
    return data.exp && data.exp > Date.now() / 1000;
  } catch (e) {
    return false;
  }
}

// Usage in Express route
app.get('/api/data', secureRsaDecrypt(fs.readFileSync('private.pem', 'utf8')), (req, res) => {
  res.json({ message: 'Secure data', user: req.auth.payload.sub });
});

Key security practices in this implementation:

  • All error conditions (invalid base64, decryption failure, invalid padding, invalid payload structure) return the exact same HTTP 401 response with identical messaging
  • No error details are logged to the response or passed to error middleware that could create timing differences
  • The decryption attempt and payload validation occur in the same synchronous try/catch block to minimize timing variations
  • For high-security applications, consider adding artificial delays to further obscure timing differences, though constant-time error handling is the primary defense

Alternative approaches include using RSA-OAEP padding (which is not vulnerable to Bleichenbacher attacks) or migrating to asymmetric algorithms like ECDSA. However, if PKCS#1 v1.5 must be used for compatibility, the constant-time error handling pattern above is essential. middleBrick's LLM/AI security checks also include probing for timing vulnerabilities in RSA endpoints, helping identify implementations that may inadvertently leak padding oracle information through response timing or error message variations.

Frequently Asked Questions

Can Express.js applications be vulnerable to Bleichenbacher attacks if they only use HTTPS?
Yes. While HTTPS protects against network eavesdropping, the Bleichenbacher attack targets the application-layer RSA decryption logic. If your Express endpoint decrypts RSA-encoded tokens (e.g., for custom auth or API keys) using PKCS#1 v1.5 padding, it remains vulnerable regardless of transport encryption. The attack works by interacting with the decryption endpoint directly, not by intercepting TLS traffic.
Does using Node.js' built-in crypto module automatically protect against Bleichenbacher attacks?
No. The Node.js crypto module provides the cryptographic primitives but does not enforce secure usage patterns. Developers must implement constant-time error handling themselves. Simply calling crypto.privateDecrypt with PKCS#1 v1.5 padding and returning different errors for padding failures versus other issues creates a padding oracle, which attackers can exploit regardless of the underlying library's correctness.