Password Spraying in Fastapi with Jwt Tokens
Password Spraying in Fastapi with Jwt Tokens — how this specific combination creates or exposes the vulnerability
Password spraying is an authentication-focused attack where one attacker-controlled credential is tested against many accounts. When an API built with FastAPI uses JSON Web Tokens (JWT) for access control, password spraying can still be effective if authentication endpoints do not enforce rate limits or otherwise distinguish between invalid credentials and non-existent users. Because JWTs are typically issued after a successful username and password check, attackers probe for valid accounts by sending a single common password (e.g., Password123 or Company2025!) against a list of usernames. If the endpoint leaks whether the username exists and responds with the same status code and generic message for both invalid user and wrong password, the attacker can infer valid accounts without triggering per-account lockouts.
In FastAPI, if the login route parses JSON, verifies the user in a database, and then signs a JWT using a library such as PyJWT or python-jose, subtle implementation choices can amplify the risk. For example, querying the user by username before checking the password means timing differences may reveal whether the username exists. Additionally, if the token issuance path does not bind the JWT tightly to authentication context (for example, not tying the jti or session state to a server-side record), an attacker who discovers valid credentials can reuse the JWT until it expires. Common weaknesses tied to this pattern include missing rate limiting on the token endpoint, missing account lockout or suspicious activity detection, and returning detailed error messages that disclose user existence or backend details.
The OWASP API Security Top 10 highlights Broken Object Level Authorization (BOLA) and Credential Stuffing as relevant concerns when tokens are used for authorization without strong authentication safeguards. Password spraying against JWT-secured FastAPI endpoints can therefore lead to unauthorized access, lateral movement, and token replay if weak passwords are discovered. Because the attack is unauthenticated, it maps well to the unauthenticated attack surface that middleBrick scans, testing endpoints that issue tokens without requiring prior credentials.
Real-world examples illustrate the risk. An endpoint like POST /api/auth/login that accepts {"username":"alice","password":"..."} and returns a signed JWT may respond with 401 and {"detail":"Incorrect username or password"} for any input. If no rate limiting exists, middleBrick’s authentication checks can flag this surface as risky because the uniform response and lack of throttling enable spraying. Similarly, if the token endpoint issues a JWT with excessive lifetime or without additional context checks, the value of discovered credentials remains high for attackers.
To detect this during a scan, middleBrick runs checks in parallel, including Authentication, Rate Limiting, and Input Validation against the login and token endpoints. The scanner submits varied usernames with a single password while observing status codes, response timing consistency, and token issuance behavior. Findings are mapped to compliance frameworks such as OWASP API Top 10 and SOC2, and prioritized with remediation guidance rather than attempting to fix the service automatically.
Jwt Tokens-Specific Remediation in Fastapi — concrete code fixes
Remediation focuses on making authentication endpoints resilient to password spraying and ensuring JWT usage does not weaken account security. Key measures include strict rate limiting on token endpoints, uniform error responses, secure password handling, and binding JWTs to authentication context where practical.
Rate limiting and uniform responses
Apply rate limiting to the login endpoint so that an account or IP cannot perform excessive sign-in attempts in a short period. FastAPI applications often use middleware or dependencies for this purpose. Also standardize HTTP status codes and response bodies for failed authentication to avoid leaking whether a username exists.
from fastapi import FastAPI, HTTPException, Request, Depends
from fastapi.security import HTTPBearer
import time
app = FastAPI()
security = HTTPBearer()
# Simple in-memory rate limit store; production systems should use Redis or similar.
attempts = {}
def rate_limit(username: str, window: int = 60, max_attempts: int = 5) -> bool:
now = time.time()
window_start = now - window
attempts[username] = [t for t in attempts.get(username, []) if t > window_start]
if len(attempts[username]) >= max_attempts:
return False
attempts[username].append(now)
return True
@app.post("/api/auth/login")
async def login(request: Request):
body = await request.json()
username = body.get("username", "")
password = body.get("password", "")
# Always run the check to avoid timing leaks; in real code, verify a hash.
if not rate_limit(username):
raise HTTPException(status_code=429, detail="Too many attempts")
# Simulated user verification; use a constant-time comparison in practice.
user = get_user_by_username(username)
if not user or not verify_password(password, user["password_hash"]):
raise HTTPException(status_code=401, detail="Incorrect username or password")
token = create_jwt(user["sub"])
return {"access_token": token, "token_type": "bearer"}
Secure JWT issuance and usage
When issuing JWTs, include a minimal set of claims and consider adding a jti (JWT ID) to support revocation checks if your architecture requires it. Use strong algorithms like RS256 with proper key management. Avoid embedding sensitive data in the token payload.
from datetime import datetime, timedelta
from jose import jwt
def create_jwt(subject: str) -> str:
now = datetime.utcnow()
payload = {
"sub": subject,
"iat": now,
"exp": now + timedelta(minutes=15),
"jti": "unique-identifier-here", # e.g., uuid4().hex
}
# Use environment-managed private key in production.
return jwt.encode(payload, key="your-private-key", algorithm="RS256")
Defense-in-depth measures
- Enforce strong password policies to reduce the effectiveness of spraying even if accounts are discovered.
- Implement multi-factor authentication for sensitive operations.
- Log suspicious authentication patterns for detection and response, but avoid logging raw passwords.
- Use constant-time comparison functions when checking password hashes to mitigate timing attacks.
These fixes reduce the attack surface for password spraying against JWT-based FastAPI services and align with best practices for token-based authentication. middleBrick’s scans can validate the effectiveness of these controls by checking authentication endpoints and token issuance behavior without requiring credentials.