Implementing CSRF Protection
1. Understanding CSRF Attacks
| Aspect | Detail |
| Attack | Attacker tricks browser into sending authenticated request |
| Requires | Cookie-based session + state-changing endpoint |
| Vector | Image, form auto-submit, fetch from attacker page |
2. Implementing CSRF Tokens
Example: Synchronizer token
// Issue: tie to session, embed in form
app.get("/form", (req, res) => {
req.session.csrf = crypto.randomBytes(32).toString("hex");
res.render("form", { csrf: req.session.csrf });
});
// Verify
app.post("/action", (req, res) => {
if (req.body._csrf !== req.session.csrf) return res.status(403).end();
// ...
});
3. Using Double Submit Cookie Pattern
| Step | Detail |
| Set cookie | Random token in cookie (not HttpOnly) |
| Send header | JS reads cookie, sends in X-CSRF-Token |
| Server compares | Cookie value == header value |
| Better | HMAC signed cookie (avoids cookie tossing) |
4. Implementing Token Validation
| Practice | Detail |
| Constant-time compare | Prevent timing leak |
| Per-session | Bind token to session ID |
| Per-request (optional) | Rotate after each state change |
5. Using SameSite Cookie Attribute
| Value | Behavior |
| Strict | Never sent on cross-site (best CSRF defense) |
| Lax | Sent on top-level navigation GET (default in modern browsers) |
| None | Sent always; requires Secure |
Browsers block setting custom headers cross-origin without CORS preflight. Requiring X-Requested-With: XMLHttpRequest blocks simple-request CSRF.
7. Using Origin and Referer Headers
Example: Origin check
function checkOrigin(req, res, next) {
const o = req.headers.origin || req.headers.referer;
if (!o || !o.startsWith("https://app.example.com")) return res.status(403).end();
next();
}
8. Implementing CSRF Middleware
| Library | Detail |
| Express | csurf (deprecated) → csrf-csrf, lusca |
| Django | CsrfViewMiddleware (built-in) |
| Spring | CsrfFilter (default on) |
| Rails | protect_from_forgery |
9. Handling Token Rotation
| When | Detail |
| After login | Rotate session + CSRF token |
| After privilege change | New token |
| Per-request (high security) | Single-use tokens |
10. Implementing Exempting Safe Methods
| Method | CSRF Check |
| GET / HEAD / OPTIONS | No (must be side-effect free) |
| POST / PUT / DELETE / PATCH | Required |
| Anti-pattern | State change on GET (e.g., /delete?id=1) |