| On by default | Yes — CsrfViewMiddleware is in the default MIDDLEWARE list | Yes — default_protect_from_forgery since 5.2 | Yes — CsrfFilter is on unless you disable it | Yes — for the web middleware group | Razor Pages and MVC views yes; Web API controllers no | No — nothing is built in | No, but net/http ships CrossOriginProtection since Go 1.25 |
|---|
| Pattern | Masked double-submit; synchronizer with CSRF_USE_SESSIONS | Synchronizer, session-stored, XOR-masked | Synchronizer (HttpSessionCsrfTokenRepository) | Synchronizer plus an XSRF-TOKEN mirror cookie | Encrypted token pair, bound to the authenticated user | Whatever you install | Fetch metadata (Sec-Fetch-Site), or gorilla/csrf for tokens |
|---|
| Token storage | csrftoken cookie, or the session | Session | Session, or an XSRF-TOKEN cookie | Session plus an encrypted cookie | .AspNetCore.Antiforgery.* cookie | — | — (header-based), or a cookie with gorilla/csrf |
|---|
| Form helper | {% csrf_token %} | form_with and csrf_meta_tags | Thymeleaf injects _csrf automatically | @csrf | The form tag helper injects it automatically | — | csrf.TemplateField |
|---|
| AJAX header | X-CSRFToken | X-CSRF-Token | X-CSRF-TOKEN or X-XSRF-TOKEN | X-CSRF-TOKEN or X-XSRF-TOKEN | Configurable via options.HeaderName | Convention only | X-CSRF-Token |
|---|
| Origin / Referer check | Yes — Origin against CSRF_TRUSTED_ORIGINS since 4.0, Referer fallback on HTTPS | Yes — forgery_protection_origin_check | No | No | No | No | Yes — Sec-Fetch-Site with an Origin fallback |
|---|
| Methods treated as safe | GET HEAD OPTIONS TRACE | GET HEAD | GET HEAD TRACE OPTIONS | GET HEAD OPTIONS | GET HEAD OPTIONS TRACE | — | GET HEAD OPTIONS |
|---|
| Session cookie SameSite default | Lax (SESSION_COOKIE_SAMESITE) | Lax since 5.2 | Unset — server.servlet.session.cookie.same-site has no default | lax (config/session.php) | Lax on the auth cookie; the antiforgery cookie itself is Strict | Unset — express-session sets nothing | Unset — you set it yourself |
|---|
| Escape hatch | @csrf_exempt | skip_forgery_protection, or with: :null_session | .csrf(c -> c.ignoringRequestMatchers(...)) or .disable() | validateCsrfTokens(except: [...]) | [IgnoreAntiforgeryToken] | — | AddTrustedOrigin, or simply not wrapping the mux |
|---|
| Biggest footgun | @csrf_exempt on API views; DRF SessionAuthentication is checked but TokenAuthentication skips CSRF entirely | with: :null_session on a controller that still uses cookie sessions — the request proceeds with an empty session instead of failing | .csrf().disable() copied from a stateless-JWT tutorial into a cookie-session app; withHttpOnlyFalse() degrades it to plain double-submit | Wildcards in the except list; Sanctum SPA mode with a wrong SANCTUM_STATEFUL_DOMAINS | [ApiController] plus cookie auth means no antiforgery runs at all | csurf was deprecated and archived in 2022; express.json({type:'*/*'}) reopens the text/plain vector | Forgetting to wrap the mux; gorilla/csrf without TrustedOrigins behind a proxy |
|---|
| Recommended 2026 baseline | Keep the defaults, add a __Host- prefix and SameSite=Lax | Keep the defaults | CookieCsrfTokenRepository + XorCsrfTokenRequestAttributeHandler, plus your own Origin check | Keep the defaults and keep except empty | [AutoValidateAntiforgeryToken] globally, including API controllers | csrf-csrf (signed double-submit) plus a Sec-Fetch-Site rejection | http.NewCrossOriginProtection() wrapping the mux |
|---|