HIGH cross site request forgeryfastapibasic auth

Cross Site Request Forgery in Fastapi with Basic Auth

Cross Site Request Forgery in Fastapi with Basic Auth — how this specific combination creates or exposes the vulnerability

Cross Site Request Forgery (CSRF) is a threat where an attacker tricks a victim’s browser into making unwanted authenticated requests on a site where the user is already authenticated. When Basic Auth is used in FastAPI, credentials are typically sent via the Authorization header on every request. If your FastAPI application relies solely on Basic Auth over HTTPS and does not implement additional CSRF protections, a browser-based attacker can craft forms or scripts on a malicious site that cause the victim’s browser to send those same Authorization headers to your API endpoints.

Consider a FastAPI endpoint that performs state-changing actions (e.g., transferring funds or changing email) and only checks the Authorization header. Because browsers automatically include credentials for same-origin and cross-origin requests when credentials are accepted, an attacker can host an HTML page containing an image or form that points to your FastAPI route. If the victim visits the page while authenticated to your API, the browser attaches the Authorization header, and the request may succeed from the API’s perspective. This is especially relevant when Basic Auth is used without anti-CSRF tokens or custom headers, and when the API is consumed by web clients that maintain session-like authentication via headers.

CSRF against Basic Auth in FastAPI is not about stealing the credentials; the attacker doesn’t need to know the password. Instead, the attack leverages the browser’s automatic credential inclusion. Because Basic Auth lacks built-in CSRF mitigation (unlike cookie-based sessions with SameSite and CSRF tokens), developers must explicitly add protections if their API serves web clients that maintain authentication state across origins. Attack patterns include malicious forms on attacker-controlled domains, crafted img tags, or JavaScript that issues forged requests via fetch or XMLHttpRequest when credentials are accepted cross-origin.

In practice, you should assume that endpoints accepting state changes are CSRF-prone when only Basic Auth is used and no extra safeguards are applied. middleBrick’s checks for BOLA/IDOR and unsafe consumption help surface endpoints that may rely solely on identifier-based authentication without proper ownership checks or custom headers that can be verified as non-browser-origin. Combining proper CORS policies, requiring custom headers (such as X-Requested-With), and using anti-CSRF tokens for any browser context reduces the risk, even when Basic Auth is in use.

Basic Auth-Specific Remediation in Fastapi — concrete code fixes

To mitigate CSRF when using Basic Auth in FastAPI, combine secure transport, explicit header checks, and anti-CSRF tokens for any browser-facing endpoints. Below are concrete code examples that you can apply to reduce risk.

1. Enforce HTTPS and use secure Basic Auth

Always use HTTPS to prevent credential leakage. Use HTTPBasic from FastAPI’s security utilities, and avoid sending passwords in clear text over insecure channels.

from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
import secrets

app = FastAPI()
security = HTTPBasic()

def get_current_user(credentials: HTTPBasicCredentials = Depends(security)):
    # Replace with secure user validation, e.g., constant-time compare
    expected_user = "apiuser"
    expected_pass = "s3cr3t"
    if not (secrets.compare_digest(credentials.username, expected_user) and
            secrets.compare_digest(credentials.password, expected_pass)):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid credentials",
            headers={"WWW-Authenticate": "Basic"},
        )
    return credentials.username

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

2. Require a custom header to distinguish API from browser requests

CSRF attacks from browsers rely on automatic credential inclusion. By requiring a custom header (e.g., X-Requested-With or X-API-Key) that cannot be set cross-origin via simple HTML forms, you block forged requests initiated by attacker sites.

from fastapi import FastAPI, Depends, Header, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials

app = FastAPI()
security = HTTPBasic()

REQUIRED_HEADER = "X-Requested-With"
EXPECTED_VALUE = "XMLHttpRequest"

def get_current_user_and_validate_header(
    credentials: HTTPBasicCredentials = Depends(security),
    x_requested_with: str = Header(None),
):
    if not secrets.compare_digest(credentials.username, "apiuser") or \
       not secrets.compare_digest(credentials.password, "s3cr3t"):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid credentials",
            headers={"WWW-Authenticate": "Basic"},
        )
    if x_requested_with != EXPECTED_VALUE:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Missing or invalid custom header",
        )
    return credentials.username

@app.post(/transfer")
async def transfer(
    user: str = Depends(get_current_user_and_validate_header),
    amount: int,
    to: str,
):
    # perform transfer logic
    return {"status": "ok"}

3. Use anti-CSRF tokens for browser clients

For endpoints that serve or are called from a browser (e.g., a frontend that stores the token in session storage), issue and validate anti-CSRF tokens. Store the token server-side (e.g., in a signed session or cache) and require it in a header or form field for state-changing methods.

from fastapi import FastAPI, Depends, Form, HTTPException, status, Cookie
from fastapi.security import HTTPBasic, HTTPBasicCredentials
import secrets

app = FastAPI()
security = HTTPBasic()

# Simplified token store; use a secure server-side store in production
csrf_tokens = {}

def get_current_user(credentials: HTTPBasicCredentials = Depends(security)):
    if not secrets.compare_digest(credentials.username, "apiuser") or \
       not secrets.compare_digest(credentials.password, "s3cr3t"):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid credentials",
            headers={"WWW-Authenticate": "Basic"},
        )
    return credentials.username

@app.post("/get-csrf")
async def get_csrf_token(user: str = Depends(get_current_user), response: Response):
    token = secrets.token_urlsafe(32)
    # associate token with user/session in a secure store
    csrf_tokens[token] = user
    response.set_cookie(
        key="csrf_token",
        value=token,
        httponly=False,
        secure=True,
        samesite="strict",
    )
    return {"csrf_token": token}

@app.post("/secure-action")
async def secure_action(
    user: str = Depends(get_current_user),
    csrf_token: str = Form(...),
    cookie_token: str = Cookie(None),
):
    if csrf_token != cookie_token or csrf_token not in csrf_tokens or csrf_tokens[csrf_token] != user:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Invalid CSRF token")
    # proceed with action
    return {"status": "success"}

4. Apply strict CORS policies

Limit which origins can interact with your API. This does not replace anti-CSRF tokens but adds a layer of defense by controlling which web pages can make authenticated requests.

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()
app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://your-trusted-frontend.com"],
    allow_credentials=True,
    allow_methods=["GET", "POST"],
    allow_headers=["Authorization", "X-Requested-With"],
)

Frequently Asked Questions

Does using Basic Auth alone prevent CSRF in FastAPI?
No. Basic Auth provides authentication but does not prevent CSRF, because browsers automatically include credentials for requests to the target origin. You must add explicit CSRF protections such as custom headers, anti-CSRF tokens, or strict CORS rules.
Can middleBrick detect CSRF risks for endpoints using Basic Auth?
Yes. middleBrick runs checks such as BOLA/IDOR and unsafe consumption that can highlight endpoints relying on identifier-based authentication without proper ownership or CSRF considerations. Use the CLI (middlebrick scan ) or the dashboard to review findings and follow the provided remediation guidance.