Web App Security & OWASP Top 10
What is Cross-Site Request Forgery (CSRF) and how do anti-CSRF tokens protect state-changing POST requests?
Anti‑CSRF tokens tie each state‑changing request to a server‑generated secret, preventing forged submissions.
R
Rahul Sharma
👑 Tier 3 Elite
Aug 9, 2026 · 2 min read
CSRF tricks a victim’s browser into sending an authenticated state‑changing request to a target site. Anti‑CSRF tokens bind the request to a user‑specific secret that the attacker cannot guess, causing the server to reject forged submissions.
**How anti‑CSRF works**
1. **Token generation** – On each GET that renders a form, the server creates a cryptographically random value (e.g., 128‑bit) and stores it in the user’s session or a signed cookie (`XSRF‑TOKEN`).
2. **Token injection** – The value is embedded in the HTML, either as a hidden `` or as a JavaScript‑readable header meta tag.
3. **Client submission** – When the user submits the form (POST, PUT, DELETE), the token is sent back either in the request body or in the `X‑XSRF‑TOKEN` header (Ajax).
4. **Verification** – The server reads the token from the request and compares it to the stored value. A mismatch returns HTTP 403.
5. **Rotation** – After a successful verification, the token is regenerated to limit reuse.
**Quick comparison**
| Mechanism | Stored where | Sent via | Replay protection |
|-----------|--------------|----------|-------------------|
| Cookie‑only auth | HttpOnly cookie | Cookie header | No |
| Anti‑CSRF token | Session or signed cookie | Body / `X‑XSRF‑TOKEN` header | Yes (per‑request) |
**Express.js example (Node 18)**
```javascript
const express = require('express');
const cookieParser = require('cookie-parser');
const csurf = require('csurf');
const app = express();
app.use(cookieParser());
app.use(express.urlencoded({ extended: false }));
app.use(csurf({ cookie: { httpOnly: true, sameSite: 'strict' } }));
app.get('/form', (req, res) => {
res.send(`
Send
`);
});
app.post('/submit', (req, res) => {
res.send('OK');
});
```
**Gotcha:** If you serve the same page from a CDN that strips or rewrites the hidden input, the token never reaches the server and every POST fails with 403. Ensure the CDN respects the token field or disable edge‑side injection for those endpoints.
Read the evidence
Sources used in this thread
Open the original material, compare the claims, and form your own view.