Bleichenbacher Attack in Fastapi
How Bleichenbacher Attack Manifests in Fastapi
The Bleichenbacher attack exploits RSA PKCS#1 v1.5 padding validation to decrypt ciphertexts or forge signatures. In Fastapi applications, this vulnerability most commonly appears when handling encrypted data in request bodies or headers without proper padding validation.
Consider a Fastapi endpoint that decrypts RSA-encrypted data from a JSON payload:
from fastapi import FastAPI
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa
app = FastAPI()
@app.post("/decrypt")
def decrypt_data(encrypted_data: str):
private_key = load_private_key() # Load your private key
ciphertext = bytes.fromhex(encrypted_data)
# Vulnerable: Default PKCS1v15 padding without side-channel protection
plaintext = private_key.decrypt(
ciphertext,
padding.PKCS1v15()
)
return {"decrypted": plaintext.decode()}
This implementation is vulnerable because PKCS#1 v1.5 padding validation is deterministic and leaks information through timing differences. An attacker can send crafted ciphertexts and observe response times to gradually recover the plaintext.
Fastapi's asynchronous nature can actually worsen this vulnerability. When using async endpoints with RSA operations:
@app.post("/decrypt-async")
async def decrypt_data_async(encrypted_data: str):
private_key = load_private_key()
ciphertext = bytes.fromhex(encrypted_data)
# Still vulnerable despite async context
plaintext = await run_in_executor(None, private_key.decrypt, ciphertext, padding.PKCS1v15())
return {"decrypted": plaintext.decode()}
The timing differences become even more pronounced due to context switching between async tasks, providing attackers with additional signals.
Another Fastapi-specific manifestation occurs with JWT token validation. Many Fastapi applications use PyJWT or similar libraries that might default to vulnerable RSA padding:
from fastapi import HTTPException, Depends
from jose import JWTError, jwt
from fastapi.security import OAuth2PasswordBearer
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
algorithm = "RS256" # Uses PKCS#1 v1.5 under the hood
@app.post("/protected")
async def protected_route(token: str = Depends(oauth2_scheme)):
try:
# Vulnerable if the underlying library uses PKCS#1 v1.5 without countermeasures
payload = jwt.decode(token, public_key, algorithms=[algorithm])
return {"data": payload}
except JWTError:
raise HTTPException(status_code=401, detail="Invalid token")
The vulnerability is particularly dangerous in Fastapi because the framework's design encourages rapid development of authentication endpoints, where developers might unknowingly use insecure defaults.
Fastapi-Specific Detection
Detecting Bleichenbacher vulnerabilities in Fastapi applications requires both static code analysis and runtime scanning. For static analysis, look for these patterns in your Fastapi codebase:
# Patterns to search for:
# 1. PKCS1v15 padding usage
from cryptography.hazmat.primitives.asymmetric import padding
padding.PKCS1v15() # Vulnerable
# 2. JWT libraries that might use PKCS#1 v1.5
import jwt
jwt.decode(..., algorithms=["RS256"]) # Check underlying implementation
# 3. Custom RSA decryption endpoints
@app.post("/decrypt")
async def decrypt_endpoint(encrypted_data: str):
# Look for private_key.decrypt calls
middleBrick's API security scanner specifically detects Bleichenbacher vulnerabilities in Fastapi applications. The scanner tests for timing side-channels by:
- Sending crafted ciphertexts with slight variations
- Measuring response time differences (vulnerable implementations show measurable timing variations)
- Analyzing error messages for padding validation information leakage
- Checking for unauthenticated decryption endpoints
Using middleBrick's CLI to scan your Fastapi API:
npm install -g middlebrick
middlebrick scan https://your-fastapi-app.com/api/decrypt
The scanner will report findings with severity levels and specific remediation guidance. For Bleichenbacher attacks, middleBrick checks:
- Whether endpoints accept encrypted data without authentication
- Timing consistency across decryption attempts
- Error message specificity that might reveal padding validation failures
- Usage of vulnerable padding schemes in the codebase
middleBrick's LLM security features also scan for AI-related endpoints that might be vulnerable to combined attacks, though Bleichenbacher specifically targets RSA padding.
Fastapi-Specific Remediation
Fixing Bleichenbacher vulnerabilities in Fastapi requires replacing vulnerable padding schemes with secure alternatives. The most straightforward fix is switching from PKCS#1 v1.5 to OAEP padding:
from fastapi import FastAPI
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes
app = FastAPI()
@app.post("/decrypt-secure")
def decrypt_data_secure(encrypted_data: str):
private_key = load_private_key()
ciphertext = bytes.fromhex(encrypted_data)
# Secure: OAEP padding with MGF1 and SHA-256
plaintext = private_key.decrypt(
ciphertext,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return {"decrypted": plaintext.decode()}
OAEP padding provides semantic security and is resistant to Bleichenbacher-style attacks because it uses randomization and doesn't leak padding validation information through timing.
For JWT token validation in Fastapi, ensure your JWT library uses secure RSA padding. With PyJWT:
from fastapi import HTTPException, Depends
from jose import JWTError, jwt
from fastapi.security import OAuth2PasswordBearer
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
algorithm = "RS256" # Verify PyJWT uses secure padding
@app.post("/protected-secure")
async def protected_route_secure(token: str = Depends(oauth2_scheme)):
try:
# Ensure your JWT library is up-to-date and uses secure padding
payload = jwt.decode(token, public_key, algorithms=[algorithm])
return {"data": payload}
except JWTError:
raise HTTPException(status_code=401, detail="Invalid token")
For maximum security, add constant-time comparison for any cryptographic operations:
from cryptography.hazmat.primitives import constant_time
@app.post("/verify-signature")
def verify_signature(data: str, signature: str):
public_key = load_public_key()
data_bytes = data.encode()
signature_bytes = bytes.fromhex(signature)
# Constant-time verification
try:
public_key.verify(
signature_bytes,
data_bytes,
padding.PKCS1v15(), # Only for verification, not decryption
hashes.SHA256()
)
is_valid = True
except Exception:
is_valid = False
# Always perform constant-time comparison
constant_time.bytes_eq(b"valid" if is_valid else b"invalid", b"valid")
return {"valid": is_valid}
Integrate these security checks into your Fastapi CI/CD pipeline using middleBrick's GitHub Action:
- name: Run middleBrick Security Scan
uses: middlebrick/middlebrick-action@v1
with:
api-url: "https://staging.your-app.com"
fail-on-severity: "high"
token: ${{ secrets.MIDDLEBRICK_TOKEN }}
This ensures Bleichenbacher vulnerabilities are caught before deployment. The Pro plan's continuous monitoring can also periodically rescan your production Fastapi APIs to detect any configuration changes that might reintroduce vulnerabilities.