Broken Authentication in Fastapi
How Broken Authentication Manifests in Fastapi
Broken authentication in Fastapi applications typically emerges through several specific implementation patterns that developers often overlook. The most common vulnerability occurs when developers rely on Fastapi's default behavior without implementing proper session management or token validation.
A critical weakness appears when using Fastapi's Depends() for authentication without proper scope validation. Consider this vulnerable pattern:
from fastapi import Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="auth/token")
async def get_current_user(token: str = Depends(oauth2_scheme)):
credentials_exception = HTTPException(
status_code=401,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
# Missing token validation logic!
return User(id=1, username="default")
@app.get("/user/profile")
async def read_user_profile(current_user: User = Depends(get_current_user)):
return current_user
This code accepts any token without validation, allowing attackers to bypass authentication entirely. The get_current_user function returns a valid User object regardless of the token's authenticity.
Another Fastapi-specific vulnerability involves improper dependency injection for authentication. When developers create authentication dependencies that don't properly propagate errors or validate permissions:
async def get_admin_user(token: str = Depends(oauth2_scheme)):
user = await get_user_from_token(token)
if user.role != "admin":
raise HTTPException(status_code=401, detail="Admin access required")
return user
@app.get("/admin/users")
async def read_admin_users(current_user: User = Depends(get_admin_user)):
return await get_all_users()
The vulnerability here is that the dependency chain breaks if get_user_from_token fails silently, potentially returning None and causing downstream errors that could be exploited.
Fastapi's async nature introduces unique timing-based authentication bypass opportunities. When authentication checks are performed asynchronously without proper error handling:
async def get_current_user(token: str = Depends(oauth2_scheme)):
user = await verify_token_async(token)
if user is None:
# Race condition: response might be sent before exception
raise HTTPException(status_code=401)
return user
Attackers can exploit the brief window between token verification failure and exception raising, especially under high load where Fastapi's event loop behavior becomes unpredictable.
Fastapi-Specific Detection
Detecting broken authentication in Fastapi applications requires understanding both the framework's architecture and common vulnerability patterns. middleBrick's black-box scanning approach is particularly effective for Fastapi APIs because it tests the actual runtime behavior without needing source code access.
The scanner identifies Fastapi-specific authentication weaknesses by examining endpoint responses to various authentication scenarios. For instance, it tests whether endpoints that should require authentication accept requests without tokens, or whether different authentication schemes are properly isolated.
middleBrick's authentication detection includes these Fastapi-relevant checks:
{
"authentication_checks": [
"Missing token validation on protected endpoints",
"Bearer token bypass attempts",
"OAuth2 flow implementation verification",
"Dependency injection authentication chain validation",
"Async authentication race condition testing"
]
}
The scanner sends crafted requests to Fastapi endpoints to verify authentication enforcement. It attempts to access protected routes without tokens, with invalid tokens, and with tokens that should have insufficient permissions. Fastapi's automatic OpenAPI generation helps middleBrick understand the expected authentication requirements for each endpoint.
For Fastapi applications using Pydantic models for user data, middleBrick specifically tests for property authorization vulnerabilities where authenticated users might access data belonging to other users through IDOR (Insecure Direct Object Reference) attacks:
@app.get("/users/{user_id}")
async def read_user(user_id: int, current_user: User = Depends(get_current_user)):
user = await get_user_by_id(user_id)
if user is None:
raise HTTPException(status_code=404)
return user
middleBrick detects if authenticated users can access any user ID by systematically testing sequential user IDs and analyzing response patterns.
The scanner also identifies Fastapi's default error responses that might leak information about authentication implementation. When Fastapi returns detailed error messages about missing or invalid tokens, attackers can use this information to craft more effective attacks.
Fastapi-Specific Remediation
Securing Fastapi authentication requires implementing proper token validation, scope checking, and error handling. The foundation is a robust authentication dependency that validates tokens before allowing access:
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from jose import JWTError, jwt
from datetime import datetime
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="auth/token")
async def get_current_user(token: str = Depends(oauth2_scheme)):
try:
payload = jwt.decode(
token,
SECRET_KEY,
algorithms=[ALGORITHM]
)
username: str = payload.get("sub")
if username is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication credentials",
headers={"WWW-Authenticate": "Bearer"},
)
user = get_user_from_database(username)
if user is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication credentials",
headers={"WWW-Authenticate": "Bearer"},
)
return user
except JWTError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication credentials",
headers={"WWW-Authenticate": "Bearer"},
)
This implementation ensures tokens are cryptographically validated before any user data is accessed, preventing the bypass vulnerabilities common in Fastapi applications.
For role-based access control in Fastapi, implement scoped dependencies that properly validate permissions:
async def get_current_active_user(
current_user: User = Depends(get_current_user)
):
if current_user.disabled:
raise HTTPException(status_code=400, detail="Inactive user")
return current_user
async def get_current_active_superuser(
current_active_user: User = Depends(get_current_active_user)
):
if current_active_user.role != "superuser":
raise HTTPException(status_code=400, detail="Not enough permissions")
return current_active_user
This dependency chain ensures that each layer of authentication and authorization is properly validated before access is granted.
Fastapi's async capabilities require special attention to authentication timing. Use proper error handling and avoid race conditions:
@app.middleware("http")
async def auth_middleware(request: Request, call_next):
# Ensure authentication is completed before processing request
if "/public/" not in request.url.path:
try:
await verify_authenticated(request)
except HTTPException as e:
return JSONResponse(
status_code=e.status_code,
content={"detail": e.detail}
)
response = await call_next(request)
return response
This middleware approach ensures authentication is enforced consistently across all endpoints, addressing Fastapi's default behavior of processing requests before authentication is complete.
Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |