Examples
Worked examples of CSRF defences across the common stacks — Laravel, Express, Rails, Django, Spring — paired with their failure modes. Use them as the reference for what \"good\" looks like in a code review.
Defensive CSRF examples in five frameworks
EXAMPLE
// ============ Laravel ============
// 1) The 'web' middleware group includes VerifyCsrfToken automatically.
// 2) Blade forms emit the hidden token with @csrf.
<form method='POST' action='/account/email'>
@csrf
<input name='email' type='email'>
<button>Update</button>
</form>
// 3) AJAX: read XSRF-TOKEN cookie, send as X-XSRF-TOKEN header
// Laravel's axios bootstrap already does this.
// ============ Express (Node) ============
// npm i csurf cookie-parser
// import express from 'express'; import csurf from 'csurf';
// const app = express();
// app.use(cookieParser());
// const csrfProtection = csurf({ cookie: { sameSite: 'lax', httpOnly: true, secure: true } });
// app.use(csrfProtection);
// app.get('/form', (req, res) => res.render('form', { csrfToken: req.csrfToken() }));
// app.post('/submit', (req, res) => res.send('ok')); // automatic check
// ============ Rails ============
// ApplicationController inherits 'protect_from_forgery with: :exception'.
// form_with / form_for embed the authenticity_token hidden field.
// API-only apps:
// class Api::OrdersController < ApplicationController
// protect_from_forgery with: :null_session # disables redirect, raises
// end
// Header-based mode: send X-CSRF-Token from JS:
// const token = document.querySelector('meta[name="csrf-token"]').content;
// fetch('/orders', { method: 'POST', headers: { 'X-CSRF-Token': token } });
// ============ Django ============
// settings.py: 'django.middleware.csrf.CsrfViewMiddleware' is on by default.
// In templates: {% csrf_token %} inside <form>.
// Class-based views: inherit CsrfMixin / decorate with @csrf_protect.
// AJAX:
// const cookie = document.cookie.match(/csrftoken=([^;]+)/)[1];
// await fetch('/api/orders/', { method: 'POST', headers: { 'X-CSRFToken': cookie } });
// ============ Spring (Java) ============
// Spring Security enables CSRF for stateful apps by default.
// @Configuration
// public class WebSecurity {
// @Bean SecurityFilterChain chain(HttpSecurity http) throws Exception {
// return http.csrf(c -> c.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
// .ignoringRequestMatchers('/webhooks/**'))
// .build();
// }
// }
// Thymeleaf forms auto-inject _csrf token.
// SPA frontends read XSRF-TOKEN cookie, send X-XSRF-TOKEN header.
// ============ Same-site cookies — ALWAYS on, regardless of stack ============
// Laravel: config/session.php -> 'same_site' => 'lax', 'secure' => true
// Express: res.cookie('sid', sid, { sameSite: 'lax', secure: true, httpOnly: true });
// Rails: config.session_store :cookie_store, same_site: :lax, secure: true
// Django: SESSION_COOKIE_SAMESITE = 'Lax'; SESSION_COOKIE_SECURE = True
// Spring: server.servlet.session.cookie.same-site=lax + secure=true
Why it matters
For pure-JSON APIs authenticated by a bearer header (Authorization), CSRF is largely a non-issue — browsers refuse to attach a custom header on a cross-origin form submission. The CSRF defences above matter most for cookie-authenticated state-changing endpoints (the most common shape of a server-rendered app).
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
// Audit a feature end-to-end: HTML form → AJAX call → SPA mutation. // Confirm SameSite + token + Origin checks at every layer.Try it Yourself »
Discussion
Loading…