HIGH bleichenbacher attackfastapibasic auth

Bleichenbacher Attack in Fastapi with Basic Auth

Bleichenbacher Attack in Fastapi with Basic Auth — how this specific combination creates or exposes the vulnerability

A Bleichenbacher attack is a cryptographic side-channel attack originally described against PKCS#1 v1.5 padding in RSA decryption. In the API context, the term is often used to describe an attacker who probes an authentication endpoint that performs per-request cryptographic work (e.g., verifying a password hash or an HMAC) and observes timing differences that reveal information about validity. When Fastapi is combined with HTTP Basic Auth, the risk arises if the server’s credential verification logic is non-constant-time and the server returns different observable behavior—such as HTTP status codes, response times, or error messages—depending on whether the password hash or MAC is correct.

Consider a Fastapi endpoint that uses Basic Auth and performs a manual check like comparing a stored hash or HMAC. If the comparison short-circuits on the first mismatching byte (common with naive string or byte equality checks), an attacker can send many requests with slightly modified credentials and measure response times. A consistently slower response for certain password bytes allows the attacker to iteratively guess the secret, effectively performing a padding-style adaptive chosen-ciphertext attack adapted to authentication. Even when the Basic Auth credentials are correct, Fastapi may still return 401 for other reasons; if those 401 responses differ in size, headers, or timing from 200 responses, the attacker gains additional signals. In a black-box scan, middleBrick tests unauthenticated attack surfaces and flags cases where authentication endpoints appear to leak validity through timing or response differences, which is one of the 12 security checks run in parallel.

In Fastapi, a typical vulnerable pattern is to manually decode the Authorization header, extract the password, and compare it with a stored value using Python’s default equality. Because Python’s == for bytes can short-circuit, and because frameworks may raise exceptions or return different status codes based on malformed input, the observable behavior becomes information leakage. middleBrick’s LLM/AI Security checks do not apply here, but its standard authentication and input validation checks can detect endpoints where authentication logic might be susceptible to timing-based inference. The scanner cross-references the OpenAPI spec with runtime findings; if the spec documents Basic Auth but the implementation does not enforce constant-time checks or rate limiting, the finding is surfaced with severity and remediation guidance.

Basic Auth-Specific Remediation in Fastapi — concrete code fixes

To mitigate Bleichenbacher-style side-channel risks in Fastapi with HTTP Basic Auth, ensure that credential verification runs in constant time and that error paths do not leak validity. Use framework utilities that abstract safe comparison and avoid manual byte-by-byte checks. Below are two concrete approaches: one using a safe comparison helper, and one using HTTPBearer with scopes to reduce custom logic.

Example 1: Constant-time comparison with explicit 401 responses

This example decodes Basic Auth manually but uses hmac.compare_digest (constant-time) and ensures identical response shape and status code for valid and invalid credentials to minimize timing and error-message leakage.

from fastapi import Fastapi, Depends, HTTPException, Security, Header, Response
from fastapi.security import HTTPBasic, HTTPBasicCredentials
import base64
import secrets
import hmac

app = Fastapi()
security = HTTPBasic()

# A stored secret, e.g., a password or a server-side shared secret
STORED_SECRET = b"super-secret-token-12345"

def verify_credentials(credentials: HTTPBasicCredentials) -> bool:
    # Decode the provided credentials
    try:
        decoded = base64.b64decode(credentials.credentials)
    except Exception:
        decoded = b""
    # Use constant-time comparison to avoid timing leaks
    return hmac.compare_digest(decoded, STORED_SECRET)

@app.get("/secure")
async def secure_endpoint(response: Response, credentials: HTTPBasicCredentials = Security(security)):
    # Always perform the same work and return the same response shape
    if not verify_credentials(credentials):
        response.status_code = 401
        return {"error": "unauthorized"}
    return {"message": "ok"}

Example 2: Using OAuth2PasswordBearer-style dependency with hashed passwords

For password-based flows, store a hash (e.g., argon2 or bcrypt), and compare using the framework’s safe utilities. This example uses a dummy user database and shows how to avoid leaking which part of the credential is wrong.

from fastapi import Fastapi, Depends, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
import base64
import hashlib
import hmac

app = Fastapi()
security = HTTPBasic()

# Simulated user store; in practice use a database with a proper password hash
USERS = {
    "alice": hashlib.sha256(b"correct-horse-battery-staple").hexdigest()
}

def get_user_password_hash(username: str):
    # Return a fixed-length dummy hash to prevent username enumeration
    return USERS.get(username, "0" * 64)

def verify_basic_auth(credentials: HTTPBasicCredentials = Security(security)):
    try:
        decoded = base64.b64decode(credentials.credentials)
        username, password = decoded.split(b":", 1)
        username = username.decode("utf-8")
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid authentication credentials",
            headers={"WWW-Authenticate": "Basic"},
        )
    expected_hash = get_user_password_hash(username)
    provided_hash = hashlib.sha256(password).hexdigest()
    if not hmac.compare_digest(expected_hash, provided_hash):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid authentication credentials",
            headers={"WWW-Authenticate": "Basic"},
        )
    return username

@app.get("/items")
async def read_items(user: str = Depends(verify_basic_auth)):
    return {"user": user, "items": ["a", "b"]}

Additional defenses complement these code-level fixes: enforce rate limiting on authentication endpoints to reduce adaptive attack feasibility, and ensure consistent response sizes and headers for success and error cases to minimize observable side channels. middleBrick’s checks for authentication, input validation, and rate limiting can highlight where implementations deviate from safer patterns. For teams needing ongoing oversight, the Pro plan provides continuous monitoring and can integrate into CI/CD pipelines to fail builds if risk scores exceed configured thresholds.

Frequently Asked Questions

Why does Fastapi Basic Auth risk timing attacks even when it returns 401?
If the comparison of credentials is not constant-time (e.g., using == on bytes or strings), an attacker can learn which byte position mismatched earlier, and by measuring response times infer the correct secret. Returning 401 is not enough; the server must also ensure the computation and response path do not vary by secret validity.
Does middleBrick test for Bleichenbacher-style timing leaks in unauthenticated scans?
middleBrick runs authentication and input validation checks in parallel and can flag endpoints where timing or response differences suggest potential side-channel leakage. It analyzes the OpenAPI spec and runtime behavior without requiring credentials, focusing on observable endpoints.