Skip to content

Instantly share code, notes, and snippets.

@anyt
Created July 25, 2025 12:26
Show Gist options
  • Select an option

  • Save anyt/3d553b4a976af1cff822d51c3d59d55f to your computer and use it in GitHub Desktop.

Select an option

Save anyt/3d553b4a976af1cff822d51c3d59d55f to your computer and use it in GitHub Desktop.

OWASP CSRF Protection Concerns and Symfony's Response

Background

This document analyzes the OWASP security concerns raised during the development of Symfony's stateless CSRF protection feature, based on GitHub PR #58095.

OWASP Concerns Raised

Initial Challenge by @jderusse

Quote from discussion:

"OWASP discourage using this pattern and recommands using a hash/crypted value coupled to the session (or JWT lifetime) instead"

Nicolas Grekas' Defense of Symfony's Approach

1. "This is NOT the Naive Pattern"

Nicolas argues that Symfony's implementation is fundamentally different from what OWASP discourages:

"I've read that, and what I'm proposing here is significantly different from what they discourage to be considered seriously IMHO, esp with the new cookie attributes and with the style of double-submit I'm using here (which is not discussed on that page)."

2. Addressing Specific OWASP-Referenced Vulnerabilities

The OWASP page links to David Johansson's presentation about vulnerabilities. Nicolas addresses each:

"I read that doc too, and they don't apply to this PR:

• MITM are ruled out by HTTPS nowadays (and no CSRF techniques can resist to MITM anyway) • HTTPS is enforced for cookies by the __Host- prefix, which prevents overriding them from HTTP • overriding the cookie isn't enough since the double-submit happens via a custom header (which is listed as a valid CSRF-protection on that PDF and on the OWASP page) • the Origin header is checked also when available"

3. Statelessness Requirement

"Binding CSRF tokens to any server-side state is ruling out statelessness/cacheability of the strategy so I'm not looking for anything hashed/signed/etc."

Symfony's Multi-Layer Security Architecture

Primary Protection: Origin/Referer Header Validation

  • First line of defense using Origin header validation
  • Most secure approach when headers are available

Fallback Protection: Modified Double-Submit Pattern

  • Used when Origin headers are unavailable (corporate environments, etc.)
  • Enhanced with modern security features

Additional Security Hardening

  • __Host- cookie prefix: Prevents subdomain cookie injection on HTTPS
  • SameSite=Strict cookies: Strengthens CSRF protection
  • Custom headers: Harder for attackers to forge than simple cookies
  • Token clearing: Token cleared after each response to prevent reuse

Defense in Depth Philosophy

"this double-submit is not only a fallback. It's also a defense in-depth. What I mean is that if Origin is broken for any reasons, users won't be immediately exposed."

Session Degradation Protection

"When a session is found, a behavioral check is added to ensure that the validation method does not downgrade from double-submit to origin checks. This prevents attackers from exploiting potentially less secure validation methods once a more secure method has been confirmed as functional."

Technical Implementation Details

Cookie Security

  • On HTTPS: __Host- prefix prevents HTTP channel forgery
  • samesite=strict attribute for additional protection
  • Cookie cleared on response to prevent token reuse

Header-Based Validation

  • Custom header requirement makes cross-origin attacks harder
  • Cannot be set programmatically from malicious sites due to CORS

Token Management

  • Token value regenerated on every request
  • Uses cryptographically secure random generator
  • Token placed in cookie name to prevent race conditions

Community Response and Evolution

Naming Discussion

Original: "Double Submit CSRF Protection" Final: "Stateless Headers/Cookies-based CSRF Protection"

Reason for name change (@stof):

"One argument for renaming: it will avoid getting more reports in the future from people telling us that OWASP discourages the double submit pattern, because they miss that they only discourage naive double-submit."

Security Team Validation

Multiple Symfony security team members (@wouterj, @chalasr, @stof) reviewed and approved the approach after thorough analysis.

Key Differences from OWASP-Discouraged Pattern

OWASP Naive Pattern (Discouraged) Symfony's Implementation
Simple cookie matching Origin header validation + fallback
Vulnerable to subdomain attacks __Host- prefix prevents subdomain injection
Only cookie-based validation Custom header requirement
No additional protections SameSite, HTTPS enforcement, token clearing
Pure client-side generation Server-controlled validation logic
Single validation method Multi-layer defense approach

Conclusion: Sophisticated Security Engineering

This discussion demonstrates thoughtful security engineering that:

  1. Acknowledges OWASP guidelines while understanding their specific context
  2. Addresses root attack vectors rather than following rules blindly
  3. Implements defense-in-depth rather than relying on single protection
  4. Balances security with architectural needs (statelessness, HTTP caching compatibility)

Key Insight: OWASP discourages "naive" double-submit, but Symfony's implementation adds multiple security layers that specifically address the vulnerabilities OWASP was concerned about. This represents an evolution beyond the basic pattern that OWASP analyzed.

The implementation shows how careful engineering can mitigate security concerns while meeting modern architectural requirements for stateless, scalable applications.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment