@@ -34,9 +34,9 @@ unique tokens added to forms as hidden fields. The legit server validates them t
3434ensure that the request originated from the expected source and not some other
3535malicious website.
3636
37- Anti-CSRF tokens can be managed either in a stateful way: they're put in the
38- session and are unique for each user and for each kind of action, or in a
39- stateless way: they're generated on the client- side.
37+ Anti-CSRF tokens can be managed in two ways: using a ** stateful ** approach,
38+ where tokens are stored in the session and are unique per user and action; or a
39+ ** stateless ** approach, where tokens are generated on the client side.
4040
4141Installation
4242------------
@@ -106,7 +106,7 @@ protected forms, among them:
106106 field value with it.
107107
108108The most effective way to cache pages that need CSRF protected forms is to use
109- stateless CSRF tokens, see below.
109+ :ref: ` stateless CSRF tokens < csrf-stateless-tokens >`, as explained below.
110110
111111.. _csrf-protection-forms :
112112
@@ -310,6 +310,8 @@ targeted parts of the plaintext. To mitigate these attacks, and prevent an
310310attacker from guessing the CSRF tokens, a random mask is prepended to the token
311311and used to scramble it.
312312
313+ .. _csrf-stateless-tokens :
314+
313315Stateless CSRF Tokens
314316---------------------
315317
@@ -363,28 +365,31 @@ option:
363365 ;
364366 };
365367
366- Stateless CSRF tokens use a CSRF protection that doesn't need the session. This
367- means that you can cache the entire page and still have CSRF protection .
368+ Stateless CSRF tokens provide protection without relying on the session. This
369+ allows you to fully cache pages while still protecting against CSRF attacks .
368370
369- When a stateless CSRF token is checked for validity, Symfony verifies the
370- ``Origin `` and the ``Referer `` headers of the incoming HTTP request.
371+ When validating a stateless CSRF token, Symfony checks the ``Origin `` and
372+ ``Referer `` headers of the incoming HTTP request. If either header matches the
373+ application's target origin (i.e. its domain), the token is considered valid.
371374
372- If either of these headers match the target origin of the application (its domain
373- name), the CSRF token is considered valid. This relies on the app being able to
374- know its own target origin. Don't miss configuring your reverse proxy if you're
375- behind one. See :doc: `/deployment/proxies `.
375+ This mechanism relies on the application being able to determine its own origin.
376+ If you're behind a reverse proxy, make sure it's properly configured. See
377+ :doc: `/deployment/proxies `.
376378
377379Using a Default Token ID
378380~~~~~~~~~~~~~~~~~~~~~~~~
379381
380- While stateful CSRF tokens are better seggregated per form or action, stateless
381- ones don't need many token identifiers. In the previous example, ``authenticate ``
382- and ``logout `` are listed because they're the default identifiers used by the
383- Symfony Security component. The ``submit `` identifier is then listed so that
384- form types defined by the application can use it by default. The following
385- configuration - which applies only to form types declared using autofiguration
386- (the default way to declare *your * services) - will make your form types use the
387- ``submit `` token identifier by default:
382+ Stateful CSRF tokens are typically scoped per form or action, while stateless
383+ tokens don't require many identifiers.
384+
385+ In the example above, the ``authenticate `` and ``logout `` identifiers are listed
386+ because they are used by default in the Symfony Security component. The ``submit ``
387+ identifier is included so that form types defined by the application can also use
388+ CSRF protection by default.
389+
390+ The following configuration applies only to form types registered via
391+ :ref: `autoconfiguration <services-autoconfigure >` (which is the default for your
392+ own services), and it sets ``submit `` as their default token identifier:
388393
389394.. configuration-block ::
390395
@@ -433,41 +438,40 @@ option will use the stateless CSRF protection.
433438Generating CSRF Token Using Javascript
434439~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
435440
436- In addition to the ``Origin `` and ``Referer `` headers, stateless CSRF protection
437- also checks a cookie and a header (named ``csrf-token `` by default, see the
438- :ref: `CSRF configuration reference <reference-framework-csrf-protection >`).
439-
440- These extra checks are part of defense-in-depth strategies provided by the
441- stateless CSRF protection. They are optional and they require
442- `some JavaScript `_ to be activated. This JavaScript is responsible for generating
443- a crypto-safe random token when a form is submitted, then putting the token in
444- the hidden CSRF field of the form and submitting it also as a cookie and header.
445- On the server-side, the CSRF token is validated by checking the cookie and header
446- values. This "double-submit" protection relies on the same-origin policy
447- implemented by browsers and is strengthened by regenerating the token at every
448- form submission - which prevents cookie fixation issues - and by using
449- ``samesite=strict `` and ``__Host- `` cookies, which make them domain-bound and
450- HTTPS-only.
451-
452- Note that the default snippet of JavaScript provided by Symfony requires that
453- the hidden CSRF form field is either named ``_csrf_token ``, or that it has the
454- ``data-controller="csrf-protection" `` attribute. You can of course take
455- inspiration from this snippet to write your own, provided you follow the same
456- protocol.
457-
458- As a last measure, a behavioral check is added on the server-side to ensure that
459- the validation method cannot be downgraded: if and only if a session is already
460- available, successful "double-submit" is remembered and is then required for
461- subsequent requests. This prevents attackers from exploiting potentially reduced
462- validation checks once cookie and/or header validation has been confirmed as
463- effective (they're optional by default as explained above).
441+ In addition to the ``Origin `` and ``Referer `` HTTP headers, stateless CSRF protection
442+ can also validate tokens using a cookie and a header (named ``csrf-token `` by
443+ default; see the :ref: `CSRF configuration reference <reference-framework-csrf-protection >`).
444+
445+ These additional checks are part of the **defense-in-depth ** strategy provided by
446+ stateless CSRF protection. They are optional and require `some JavaScript `_ to
447+ be enabled. This JavaScript generates a cryptographically secure random token
448+ when a form is submitted. It then inserts the token into the form's hidden CSRF
449+ field and sends it in both a cookie and a request header.
450+
451+ On the server side, CSRF token validation compares the values in the cookie and
452+ the header. This "double-submit" protection relies on the browser's same-origin
453+ policy and is further hardened by:
454+
455+ * generating a new token for each submission (to prevent cookie fixation);
456+ * using ``samesite=strict `` and ``__Host- `` cookie attributes (to enforce HTTPS
457+ and limit the cookie to the current domain).
458+
459+ By default, the Symfony JavaScript snippet expects the hidden CSRF field to be
460+ named ``_csrf_token `` or to include the ``data-controller="csrf-protection" ``
461+ attribute. You can adapt this logic to your needs as long as the same protocol
462+ is followed.
463+
464+ To prevent validation from being downgraded, an extra behavioral check is performed:
465+ if (and only if) a session already exists, successful "double-submit" is remembered
466+ and becomes required for future requests. This ensures that once the optional cookie/header
467+ validation has been proven effective, it remains enforced for that session.
464468
465469.. note ::
466470
467- Enforcing successful "double-submit" for every requests is not recommended as
468- as it could lead to a broken user experience. The opportunistic approach
469- described above is preferred because it allows the application to gracefully
470- degrade to ``Origin `` / ``Referer `` checks when JavaScript is not available .
471+ Enforcing "double-submit" validation on all requests is not recommended,
472+ as it may lead to a broken user experience. The opportunistic approach
473+ described above is preferred, allowing the application to gracefully
474+ fall back to ``Origin `` / ``Referer `` checks when JavaScript is unavailable .
471475
472476.. _`Cross-site request forgery` : https://en.wikipedia.org/wiki/Cross-site_request_forgery
473477.. _`BREACH` : https://en.wikipedia.org/wiki/BREACH
0 commit comments