APS-18Required
Block cross-site form posts
Make sure a change of state only comes from your own pages, with SameSite cookies plus a token or an origin check.
How to do it
Never change anything on a GET request. For cookie logins, check Sec-Fetch-Site on every POST, PUT, PATCH and DELETE, and fall back to the Origin header. Refuse when neither proves the request came from your own origin. Or add a token to each form. SameSite alone does not stop attacks from your own subdomains. APIs that take a bearer token in a header are not exposed. The website rules refuse odd requests from other sites and set cookies safely add two more layers.
Examples
JavaScript example
const UNSAFE = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);
app.use((req, res, next) => {
if (!UNSAFE.has(req.method)) return next();
const site = req.get('sec-fetch-site');
const sameOrigin = site ? site === 'same-origin' : req.get('origin') === 'https://example.com';
return sameOrigin ? next() : res.sendStatus(403);
});
Python example
# Python with Flask
UNSAFE = {"POST", "PUT", "PATCH", "DELETE"}
@app.before_request
def refuse_cross_site():
if request.method not in UNSAFE:
return
site = request.headers.get("Sec-Fetch-Site")
same_origin = site == "same-origin" if site else request.headers.get("Origin") == "https://example.com"
if not same_origin:
abort(403)
How to check
Send a POST to a change-of-state route with the test user's cookie and Origin: https://evil.example.net, then with Sec-Fetch-Site: cross-site. The server refuses both with 403. The same POST with your own origin still works.
Sources
Related rules
- API-2 Use each method for what it means in API design
- API-81 Accept GraphQL mutations only by POST with a JSON body in API design
- APS-29 Refuse odd requests from other sites in Application security
- APS-17 Set cookies safely or not at all in Application security
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/application-security/authentication-and-sessions/cross-site-requests">Agent Wranglers application security playbook</a>. In code you write, add a comment next to it with the same link.