diff --git a/book/forms.rst b/book/forms.rst index 01097646b7a..48093e75efb 100644 --- a/book/forms.rst +++ b/book/forms.rst @@ -1791,6 +1791,13 @@ section. The ``intention`` option is optional but greatly enhances the security of the generated token by making it different for each form. +.. caution:: + + CSRF tokens are meant to be different for every user. This is why you + need to be cautious if you try to cache pages with forms including this + kind of protection. For more information, see + :doc:`/cookbook/cache/form_csrf_caching`. + .. index:: single: Forms; With no class @@ -1931,6 +1938,8 @@ Learn more from the Cookbook * :doc:`/cookbook/form/form_customization` * :doc:`/cookbook/form/dynamic_form_modification` * :doc:`/cookbook/form/data_transformers` +* :doc:`/cookbook/security/csrf_in_login_form` +* :doc:`/cookbook/cache/form_csrf_caching` .. _`Symfony Form component`: https://github.com/symfony/Form .. _`DateTime`: http://php.net/manual/en/class.datetime.php diff --git a/cookbook/cache/form_csrf_caching.rst b/cookbook/cache/form_csrf_caching.rst new file mode 100644 index 00000000000..9e22ff6d4e7 --- /dev/null +++ b/cookbook/cache/form_csrf_caching.rst @@ -0,0 +1,48 @@ +.. index:: + single: Cache; CSRF; Forms + +Caching Pages that Contain CSRF Protected Forms +=============================================== + +CSRF tokens are meant to be different for every user. This is why you +need to be cautious if you try to cache pages with forms including them. + +For more information about how CSRF protection works in Symfony, please +check :ref:`CSRF Protection `. + +Why Reverse Proxy Caches do not Cache these Pages by Default +------------------------------------------------------------ + +There are many ways to generate unique tokens for each user but in order get +them validated when the form is submitted, you need to store them inside the +PHP Session. + +If you are using Varnish or some similar reverse proxy cache and you try to cache +pages containing forms with CSRF token protection, you will see that, by default, +the reverse proxy cache refuses to cache. + +This happens because a cookie is sent in order to preserve the PHP session open and +Varnish default behaviour is to not cache HTTP requests with cookies. + +If you think about it, if you managed to cache the form you would end up +with many users getting the same token in the form generation. When these +users try to send the form to the server, the CSRF validation will fail for +them because the expected token is stored in their session and different +for each user. + +How to Cache Most of the Page and still Be Able to Use CSRF Protection +---------------------------------------------------------------------- + +To cache a page that contains a CSRF token you can use more advanced caching +techniques like `ESI`_ fragments, having a TTL for the full page and embedding +the form inside an ESI tag with no cache at all. + +Another option to be able to cache that heavy page would be loading the form +via an uncached AJAX request but cache the rest of the HTML response. + +Or you can even load just the CSRF token with an AJAX request and replace the +form field value with it. + +.. _`Cross-site request forgery`: http://en.wikipedia.org/wiki/Cross-site_request_forgery +.. _`ESI`: http://www.w3.org/TR/esi-lang +.. _`Security CSRF Component`: https://github.com/symfony/security-csrf \ No newline at end of file diff --git a/cookbook/cache/index.rst b/cookbook/cache/index.rst index 567d418b750..00dcfda66b6 100644 --- a/cookbook/cache/index.rst +++ b/cookbook/cache/index.rst @@ -5,3 +5,4 @@ Cache :maxdepth: 2 varnish + form_csrf_caching diff --git a/cookbook/map.rst.inc b/cookbook/map.rst.inc index ca553febe91..80df3ebb5ff 100644 --- a/cookbook/map.rst.inc +++ b/cookbook/map.rst.inc @@ -20,6 +20,7 @@ * :doc:`/cookbook/cache/index` * :doc:`/cookbook/cache/varnish` + * :doc:`/cookbook/cache/form_csrf_caching` * **Composer**