Bleichenbacher Attack in Fastapi with Api Keys
Bleichenbacher Attack in Fastapi with Api Keys — how this specific combination creates or exposes the vulnerability
A Bleichenbacher attack is a padding oracle attack against RSA encryption that relies on an attacker submitting many carefully crafted ciphertexts and observing subtle differences in server responses to gradually decrypt data or recover the private key. When an API uses API keys for authentication but also exposes an RSA-based decryption or signature verification endpoint, the combination can create a dangerous oracle if error handling is not uniform.
In Fastapi, a typical vulnerability pattern looks like an endpoint that accepts encrypted data and an API key, decrypts using RSA-OAEP or PKCS#1 v1.5, and then performs some authorization check. If the server returns distinct error messages or HTTP status codes for padding errors versus missing/invalid API keys, an attacker can act as an oracle. By observing status codes or response bodies, the attacker can iteratively decrypt ciphertext without knowing the private key, even when API keys are required for access.
Consider a Fastapi endpoint that decrypts a token using an RSA key and expects an API key in a header. If padding failures produce a 500 with stack traces, while an invalid API key yields 401, the difference is exploitable. An attacker who can intercept or guess ciphertexts can send modified versions and infer correctness from response codes. This is especially risky when the same service uses API keys for rate-limiting or quota but does not standardize error handling across cryptographic and auth failures.
For example, if the endpoint does not validate the API key before performing RSA decryption, or if decryption runs in a timing-sensitive manner, the oracle can leak information bit by bit. Although API keys themselves are not weak, their usage in combination with non-constant-time decryption and non-uniform error responses creates an exploitable Bleichenbacher-style oracle. Attackers may recover sensitive payloads or elevate privileges by leveraging the API key as a gate while exploiting the cryptographic oracle.
middleBrick detects this class of issue under Input Validation, Authentication, and BFLA/Privilege Escalation checks, noting when error handling and timing differences could enable adaptive chosen-ciphertext attacks even when API keys are present.
Api Keys-Specific Remediation in Fastapi — concrete code fixes
To mitigate Bleichenbacher-style attacks in Fastapi when using API keys, standardize error handling, enforce constant-time comparison, and validate API keys before any cryptographic operation. Below are concrete, working examples that reduce oracle behavior and improve resilience.
Example 1: Constant-time API key validation and uniform error response
from fastapi import FastAPI, Header, HTTPException, Request
import secrets
import hmac
app = FastAPI()
# Expected API keys stored securely (e.g., hashed in production)
VALID_API_KEYS = {"s3cr3tk3y123", "an0th3rk3y456"}
def safe_compare(a: str, b: str) -> bool:
# Use constant-time comparison to avoid timing leaks
return hmac.compare_digest(a, b)
@app.post("/decrypt")
async def decrypt_data(request: Request, api_key: str = Header(None)):
# Validate API key presence using constant-time compare against a dummy key
# to avoid early branching on missing header.
dummy_key = "dummykeyformasking"
provided = api_key or ""
is_valid = any(safe_compare(provided, k) for k in VALID_API_KEYS)
# Always run a dummy comparison to reduce timing differences
safe_compare(provided, dummy_key)
if not is_valid:
# Return a generic, uniform error and a consistent HTTP status
raise HTTPException(status_code=401, detail="Unauthorized")
# Only after auth check proceed to cryptographic operations
encrypted = await request.json()
try:
# Perform decryption with proper error handling that does not distinguish
# between padding errors and other failures.
plaintext = perform_rsa_decryption(encrypted["data"])
return {"plaintext": plaintext}
except Exception:
# Generic error to avoid leaking oracle information
raise HTTPException(status_code=400, detail="Bad request")
def perform_rsa_decrypt(ciphertext: bytes) -> str:
# Placeholder for RSA decryption logic; ensure constant-time behavior
# and avoid raising specific padding exceptions to callers.
return "decrypted_data"
Example 2: Middleware to normalize responses and enforce auth-first policy
from fastapi import FastAPI, Request, HTTPException
from fastapi.middleware import Middleware
from fastapi.middleware.base import BaseHTTPMiddleware
import json
app = FastAPI()
class SecurityMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
# Ensure API key presence before allowing decryption endpoints
if request.url.path.startswith("/decrypt"):
api_key = request.headers.get("api-key")
if not api_key or not safe_compare_api_key(api_key):
return self.json_response({"error": "Unauthorized"}, status_code=401)
response = await call_next(request)
# Standardize error bodies to avoid oracle differences
if response.status_code >= 400:
body = {"error": "Request failed"}
response.body = json.dumps(body).encode()
response.status_code = 400
response.headers["Content-Type"] = "application/json"
return response
def safe_compare_api_key(key: str) -> bool:
VALID = {"s3cr3tk3y123"}
return any(hmac.compare_digest(key, k) for k in VALID)
app.add_middleware(SecurityMiddleware)
Additional recommendations include using libs that implement RSA decryption with constant-time padding checks (e.g., via cryptography with OAEP and proper exception handling), rotating API keys regularly, and employing the middlebrick CLI to scan endpoints for authentication and input validation issues. With the Pro plan you can enable continuous monitoring so changes to error handling or crypto flows are flagged early.