Clickjacking in Fastapi with Jwt Tokens
Clickjacking in Fastapi with Jwt Tokens — how this specific combination creates or exposes the vulnerability
Clickjacking is a client-side UI redress attack where an attacker tricks a user into interacting with a hidden or disguised element inside an invisible or disguised iframe. When JWT tokens are involved, the risk pattern changes: the token itself is usually not embedded in the UI, but the browser’s automatic inclusion of credentials (cookies or authorization headers) can still enable a compromised UI flow to act on behalf of an authenticated user. In Fastapi, a common misconfiguration is rendering authenticated pages that do not enforce frame isolation, even though JWTs are often used for stateless authorization via Authorization: Bearer headers. Because JWT validation typically happens on each request, if a route is reachable inside a frame and performs sensitive actions based on a valid JWT, an attacker can craft a page that overlays invisible controls or mimics UI elements to cause unintended API calls.
Consider a Fastapi app that protects endpoints with JWT verification but serves HTML pages that allow framing. An authenticated user with a valid JWT visits a malicious site. The attacker embeds the Fastapi app in an iframe and overlays transparent buttons or links that invoke state-changing routes (for example, changing email or initiating a transaction). Because the browser sends the JWT automatically (via headers injected by a frontend library or via cookies if tokens are also stored there), the server processes the request as legitimate. This becomes more impactful when the API exposes operations that do not require additional user confirmation, and the UI does not implement anti-CSRF measures alongside JWT usage. The combination of JWT-based auth and missing frame protection exposes a workflow that can be abused via clickjacking, even though the token itself is not leaked.
middleBrick can detect whether authenticated pages are missing frame-busting controls and whether sensitive actions are exposed without explicit user consent as part of its UI-related findings. This is especially relevant when OpenAPI/Swagger specs describe state-changing methods without clarifying UI protections, and runtime checks reveal endpoints that render HTML without anti-clickjacking headers. The scanner runs unauthenticated black-box checks, so it can surface missing X-Frame-Options or Content-Security-Policy frame-ancestors rules that would otherwise allow embedding.
Jwt Tokens-Specific Remediation in Fastapi — concrete code fixes
Remediation focuses on two layers: HTTP headers that prevent framing, and application-level practices that reduce the impact of clickjacking when JWTs are used. On the server side, ensure that authenticated responses include strong frame restriction headers. For Fastapi, you can add middleware or use route-specific dependencies to set headers such as X-Frame-Options and Content-Security-Policy. In addition, design sensitive UI flows to require explicit user interaction beyond simply presenting a token, and avoid embedding pages that perform critical actions inside iframes.
Below are concrete code examples for a Fastapi app using JWT Bearer authentication.
from fastapi import Fastapi, Request, Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from fastapi.middleware import Middleware
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from starlette.middleware.base import BaseHTTPMiddleware
import re
app = Fastapi()
# Simple JWT validation dependency (example)
security = HTTPBearer()
def verify_jwt(token: str) -> dict:
# Replace with real validation logic
if not token.startswith("Bearer "):
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid authorization")
payload = {"sub": "user_id_example"} # decoded payload in real code
return payload
# Middleware to set anti-clickjacking headers
class AntiClickjackingMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
response = await call_next(request)
response.headers["X-Frame-Options"] = "DENY"
response.headers["Content-Security-Policy"] = "frame-ancestors 'none'"
return response
app.add_middleware(AntiClickjackingMiddleware)
@app.get("/account")
def read_account(credentials: HTTPAuthorizationCredentials = Depends(security)):
payload = verify_jwt(credentials.credentials)
# Render an account page that should not be framed
return {"message": "Account settings", "user": payload.get("sub")}
@app.post("/transfer")
def transfer_funds(
amount: float,
to_account: str,
credentials: HTTPAuthorizationCredentials = Depends(security)
):
# Critical action: require explicit confirmation on the client side
# and ensure the endpoint is not invocable via GET or embedded forms
payload = verify_jwt(credentials.credentials)
# Process transfer with additional verification (e.g., re-auth, MFA)
return {"status": "initiated", "to": to_account}
In this example, the middleware ensures that every response includes X-Frame-Options: DENY and Content-Security-Policy: frame-ancestors 'none', which prevents the page from being embedded in an iframe. Sensitive routes should not rely solely on the presence of a JWT; they should also enforce explicit user actions and ideally require re-authentication for critical operations. On the client side, avoid rendering pages inside iframes or embedding authentication flows that could be overlaid. middleBrick’s scans can surface endpoints that lack these headers and flag them as findings, helping you prioritize remediation.