Skip to content

Fetch Metadata (Sec-Fetch-*) based CSRF protection #18361

@bgalek

Description

@bgalek

Expected Behavior

Spring Security could provide first-class, opt-in support for CSRF protection based on Fetch Metadata headers (Sec-Fetch-Site, Sec-Fetch-Mode, Sec-Fetch-Dest, Sec-Fetch-User) as a documented and supported alternative or complement to the existing token-based CSRF protection.

It should be possible to configure Spring Security to:

  • Reject state-changing requests (e.g. POST, PUT, PATCH, DELETE) when browsers send Sec-Fetch-Site: cross-site.
  • Allow same-origin (and optionally same-site) requests by default.
  • Provide simple configuration via the existing HttpSecurity.csrf() DSL.
  • Support whitelisting for endpoints that intentionally accept cross-site requests (e.g. webhooks).
  • Optionally support a “report-only” / logging mode for safe rollout.

This would make it easier for Spring applications to adopt a simpler CSRF model aligned with modern browser capabilities and OWASP guidance.

OWASP CSRF Cheat Sheet discussion on Fetch Metadata headers

CSRF protection without tokens (Miguel Grinberg)

MDN – Fetch Metadata request headers

Current Behavior

Spring Security currently supports classic CSRF protection mechanisms as stated in docs: https://docs.spring.io/spring-security/reference/servlet/exploits/csrf.html

Context

For modern SPA applications, token-based CSRF protection can be conceptually complex and operationally heavy (token propagation, caching concerns, custom clients, backend support etc.). Fetch Metadata headers provide a simpler and more intuitive model that aligns closely with how browsers already distinguish same-origin vs cross-site requests.

I can always continue to use classic CSRF tokens everywhere or rely on Origin/Referer checks by implementing a custom OncePerRequestFilter for Fetch Metadata validation. All of these work, but lack the clarity, consistency, and safety guarantees that first-class framework support would provide.

How does the spring-security team feel about this idea? :)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions