TL;DR
CSRF tricks users into performing unwanted actions on sites where they're authenticated. Protect against it with anti-CSRF tokens, SameSite cookies, and origin header validation. Modern frameworks often handle this automatically, but you need to enable it. These prompts help you implement CSRF defenses.
Token-Based CSRF Protection
Add CSRF token protection to my application.
Framework: Next.js/Express/Django
Implementation:
- Generate token on session creation
- Store token server-side (in session)
- Send token to client (cookie or response body)
- Client includes token in requests
- Server validates token matches session
For Express: npm install csurf app.use(csrf({ cookie: true }));
// Make token available to forms app.use((req, res, next) => { res.locals.csrfToken = req.csrfToken(); next(); });
For forms:
For AJAX: fetch('/api/endpoint', { method: 'POST', headers: { 'X-CSRF-Token': csrfToken }, body: JSON.stringify(data) })
SameSite Cookie Defense
Configure SameSite cookie attribute as CSRF defense.
SameSite options:
- Strict: Cookie only sent for same-site requests
- Lax: Sent for same-site + top-level navigation (default in modern browsers)
- None: Sent for all requests (requires Secure)
Recommended settings: // Session cookie Set-Cookie: session=abc123; SameSite=Lax; Secure; HttpOnly
// For APIs needing cross-site (use with caution) Set-Cookie: token=xyz; SameSite=None; Secure
For your framework:
Next.js (in API route):
res.setHeader('Set-Cookie',
session=${value}; Path=/; HttpOnly; Secure; SameSite=Lax
);
Express: res.cookie('session', value, { httpOnly: true, secure: true, sameSite: 'lax' });
Note: SameSite alone isn't complete protection. Combine with CSRF tokens for defense in depth.
SameSite=Lax has gaps: Top-level navigations with GET still send cookies. If any of your GET endpoints change state (bad practice), SameSite won't protect them. Always use tokens too.
Origin and Referer Validation
Add Origin/Referer header validation as additional CSRF defense.
Check these headers on state-changing requests:
- Origin header (set by browser, can't be spoofed)
- Referer header (fallback if Origin missing)
Implementation: function validateOrigin(req) { const origin = req.headers.origin || req.headers.referer;
if (!origin) { // Some browsers/privacy settings don't send these // Decide: reject or allow with token validation return false; }
const url = new URL(origin); const allowedOrigins = 'https://yourdomain.com', 'https://www.yourdomain.com' ;
return allowedOrigins.includes(url.origin); }
Apply to:
- POST, PUT, DELETE, PATCH requests
- Not GET or HEAD (should be read-only)
Use as additional check, not replacement for tokens.
CSRF for SPAs and APIs
Implement CSRF protection for my SPA/API architecture.
Pattern: Double Submit Cookie
- Server sets CSRF token in cookie
- JavaScript reads cookie, sends in header
- Server compares cookie value to header value
- Cross-origin requests can't read cookie to send header
Server (on login or session start): Set-Cookie: csrf_token=random123; Path=/; SameSite=Lax
Client (on each request): const csrfToken = document.cookie .split('; ') .find(c => c.startsWith('csrf_token=')) ?.split('=')1;
fetch('/api/action', { method: 'POST', headers: { 'X-CSRF-Token': csrfToken, 'Content-Type': 'application/json' }, body: JSON.stringify(data), credentials: 'include' });
Server validation: const cookieToken = req.cookies.csrf_token; const headerToken = req.headers'x-csrf-token'; if (cookieToken !== headerToken) { return res.status(403).json({ error: 'Invalid CSRF token' }); }
Pro tip: If you use JWT in Authorization headers (not cookies), CSRF isn't possible since custom headers can't be sent cross-origin. But cookie-based auth always needs CSRF protection.
How does CSRF actually work?
If you're logged into bank.com, a malicious site can include a form that POSTs to bank.com/transfer. Your browser automatically sends your bank cookies with the request, authenticating the attacker's request as you.
Can I skip CSRF protection with JSON APIs?
Only if you require a custom Content-Type header (application/json) AND use CORS to block simple requests. But it's safer to just implement CSRF tokens.