Clickjacking in Fastapi with Api Keys
Clickjacking in Fastapi with Api Keys — 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 overlapped iframe. In a Fastapi application that relies on API keys for access control, clickjacking can bypass intended authorization boundaries when sensitive actions are exposed via endpoints that do not enforce same-origin policy or frame-embedding restrictions. Even when an API key validates the request, the attack leverages the user’s authenticated session in the browser to perform actions the user did not intend, such as changing settings or initiating privileged operations.
When API keys are passed via headers or query parameters and the corresponding UI includes pages with poorly configured HTTP headers, an attacker can embed those pages in an iframe and overlay interactive controls. Because Fastapi does not set restrictive frame-related headers by default, an application may allow itself to be embedded maliciously. The presence of API keys does not mitigate clickjacking; it can actually make the impact worse if the key is leaked through referrer headers or if the UI uses the key to authorize actions that lack additional context checks. For example, an endpoint like /transfer that requires a valid API key in a header could be invoked through a forged form on a malicious site if the response is allowed to be framed.
Middleware that only validates API keys at the entry point does not protect against clickjacking because the browser will still send credentials (cookies, authorization headers) with the forged request if the user is authenticated. This is why defense in depth is required: secure the UI and API surfaces with anti-clickjacking headers, frame-ancestors directives, and explicit design of state-changing operations to include additional context such as CSRF tokens or SameSite cookies. Without these controls, the combination of Fastapi routes protected only by API keys and pages that permit embedding creates a pathway for attackers to trick users into performing unintended authenticated actions.
Api Keys-Specific Remediation in Fastapi — concrete code fixes
Remediation for clickjacking in Fastapi should focus on preventing unauthorized embedding of responses while maintaining secure handling of API keys. Use HTTP headers to enforce strict frame policies and ensure that sensitive endpoints do not rely on API keys alone for authorization of UI actions. Below are concrete patterns and code examples to implement these protections.
Set frame-ancestors and content-security-policy headers
Configure middleware to deny framing of sensitive routes. Using Frame-Options and Content-Security-Policy with frame-ancestors ensures that browsers will not render responses in iframes unless explicitly allowed.
from fastapi import FastAPI, Request
from starlette.middleware.base import BaseHTTPMiddleware
class SecurityHeadersMiddleware(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 = FastAPI()
app.add_middleware(SecurityHeadersMiddleware)
Use SameSite and Secure cookies for session-backed flows
If your API keys are used in cookie-based authentication paths, set SameSite and Secure attributes to reduce the risk of credentials being sent in cross-site requests.
from fastapi import FastAPI, Response
from fastapi.responses import JSONResponse
app = FastAPI()
@app.post("/login")
async def login(response: Response):
response.set_cookie(
key="session_id",
value="example_value",
httponly=True,
secure=True,
samesite="strict",
)
return {"status": "ok"}
Require per-request context for sensitive actions
For endpoints that perform critical operations, require additional context beyond the API key, such as a CSRF token or a custom header that cannot be set by a malicious site. This ensures that even if a request is forged in an iframe, it will be rejected due to missing or incorrect context.
from fastapi import FastAPI, Header, HTTPException
app = FastAPI()
SAFE_HEADERS = {"x-requested-with": "XMLHttpRequest"}
@app.post("/transfer")
async def transfer(
api_key: str,
x_requested_with: str = Header(None),
):
if api_key != "expected_key" or x_requested_with != SAFE_HEADERS["x-requested-with"]:
raise HTTPException(status_code=403, detail="Forbidden")
return {"status": "transfer initiated"}
Validate Origin and Referer headers for sensitive endpoints
For APIs that are invoked from browser-based clients, validate the Origin or Referer header to ensure requests originate from expected sources. Combine this with strict CORS configuration to reduce the attack surface.
from fastapi import FastAPI, Request, HTTPException
app = FastAPI()
ALLOWED_ORIGINS = {"https://app.yourdomain.com"}
@app.middleware("http")
async def validate_origin(request: Request, call_next):
origin = request.headers.get("origin")
referer = request.headers.get("referer")
if origin and origin not in ALLOWED_ORIGINS:
raise HTTPException(status_code=403, detail="Invalid origin")
if referer and not referer.startswith(tuple(ALLOWED_ORIGINS)):
raise HTTPException(status_code=403, detail="Invalid referer")
response = await call_next(request)
return response