Cross Site Request Forgery in Chi with Api Keys
Cross Site Request Forgery in Chi with Api Keys — how this specific combination creates or exposes the vulnerability
Cross Site Request Forgery (CSRF) in a Chi application becomes more nuanced when developers rely on API keys for authentication. API keys are typically static credentials that are often stored in client-side code or transmitted in HTTP headers. When these keys are used without additional protections, an attacker can trick a user’s browser into making unintended authenticated requests to the Chi backend, leveraging the user’s existing permissions signaled by the key.
In Chi, routes are composed as a series of matchers and handlers. If an endpoint that mutates state (e.g., changing a user’s email or initiating a fund transfer) relies solely on an API key passed via a header or query parameter, and does not verify the request origin, the endpoint is vulnerable to CSRF. A malicious site can embed an image or form submission pointing to that endpoint. When the victim’s browser includes the API key automatically — either via cookies if the key is stored in a session cookie, or via JavaScript that reads the key and adds it to headers — the request is executed with the victim’s privileges.
Consider a Chi handler that uses an API key passed as a Bearer token in the Authorization header:
open import Http
open import Data.String
apiKeyHandler : Handler String
apiKeyHandler = route "/transfer" >= method PUT >= authKey >= ok "Transferred"
where
authKey : Middleware String
authKey = do
key ← header "Authorization"
if key == "Bearer secret-api-key-123" then continue else throw "Unauthorized"
If this endpoint does not validate the Origin or Referer headers, and the API key is accessible to JavaScript (e.g., stored in a token read by frontend code), an attacker can construct a form on a malicious site:
<form action="https://api.example.com/transfer" method="PUT" id="csrfForm">
<input type="hidden" name="amount" value="1000" />
<input type="hidden" name="to" value="attacker" />
</form>
<script>document.getElementById('csrfForm').submit();</script>
When the victim visits the attacker’s page, the browser sends the request with the stored Authorization header, and the Chi endpoint processes the transfer. This illustrates how combining Chi’s routing with API-key-only authentication creates a CSRF surface: the key is treated as a bearer credential, and if it leaks or is accessible to scripts, the boundary between attacker and victim blurs.
Even when API keys are stored in cookies, CSRF remains possible if the cookie is not accompanied by SameSite=Strict or SameSite=Lax and lacks Secure and HttpOnly flags. Chi applications that parse keys from cookies must ensure these protections are enforced at the session or middleware layer, complementing route-level checks.
Api Keys-Specific Remediation in Chi — concrete code fixes
Remediation focuses on ensuring that API keys do not act as the sole CSRF defense and that requests are tied to the expected origin and context. Below are concrete Chi patterns that reduce risk.
1. Validate Origin and Referer headers
Add middleware that checks the origin of incoming requests for state-changing routes. This is not a complete defense (due to potential header omission), but it raises the bar significantly:
corsSafe : Middleware String
corsSafe = do
origin ← header "Origin"
let allowed = ["https://trusted.example.com"]
if origin ∈ allowed then continue else throw "Invalid origin"
apiKeyHandlerSecure : Handler String
apiKeyHandlerSecure = route "/transfer" >= method PUT >= corsSafe >= authKey >= ok "Transferred"
2. Use anti-CSRF tokens (synchronizer token pattern)
Generate a per-session token on the server, store it in a SameSite=Lax; Secure; HttpOnly cookie, and require it in a header or form field for mutations:
type Session = { csrfToken : String }
setCsrfCookie : Session → Response → Response
setCsrfCookie sess resp = setCookie "csrf-token" sess.csrfToken
{ path = "/", secure = true, httpOnly = true, sameSite = Left Lax }
validateCsrf : String → Middleware String
validateCsrf expected = do
token ← header "X-CSRF-Token"
if token == expected then continue else throw "CSRF token mismatch"
secureTransfer : Handler String
secureTransfer = route "/transfer" >= method PUT >= validateCsrf "from-session" >= authKey >= ok "Transferred"
3. Avoid storing API keys in client-side accessible storage
Do not embed API keys in JavaScript that can be read by third-party scripts. If client-side code must call protected endpoints, use short-lived OAuth tokens or session cookies with SameSite=Lax and Secure, rather than static API keys in headers.
4. Combine with standard CSRF protections when using frameworks
If integrating Chi with frontend frameworks, ensure the framework’s CSRF mechanisms (e.g., Angular’s $http default headers, or custom fetch wrappers) include the anti-CSRF token on every mutating request.
These steps ensure that API keys in Chi are not the only line of defense and that requests are verified with respect to origin and intent, mitigating CSRF while preserving the utility of key-based authentication.