|
| 1 | +.. index:: |
| 2 | + single: Cache; CSRF; Forms |
| 3 | + |
| 4 | +Caching Pages that Contain CSRF Protected Forms |
| 5 | +=============================================== |
| 6 | + |
| 7 | +CSRF tokens are meant to be different for every user. This is why you |
| 8 | +need to be cautious if you try to cache pages with forms including them. |
| 9 | + |
| 10 | +For more information about how CSRF protection works in Symfony, please |
| 11 | +check :ref:`CSRF Protection <forms-csrf>`. |
| 12 | + |
| 13 | +Why Reverse Proxy Caches do not Cache these Pages by Default |
| 14 | +------------------------------------------------------------ |
| 15 | + |
| 16 | +There are many ways to generate unique tokens for each user but in order get |
| 17 | +them validated when the form is submitted, you need to store them inside the |
| 18 | +PHP Session. |
| 19 | + |
| 20 | +If you are using Varnish or some similar reverse proxy cache and you try to cache |
| 21 | +pages containing forms with CSRF token protection, you will see that, by default, |
| 22 | +the reverse proxy cache refuses to cache. |
| 23 | + |
| 24 | +This happens because a cookie is sent in order to preserve the PHP session open and |
| 25 | +Varnish default behaviour is to not cache HTTP requests with cookies. |
| 26 | + |
| 27 | +If you think about it, if you managed to cache the form you would end up |
| 28 | +with many users getting the same token in the form generation. When these |
| 29 | +users try to send the form to the server, the CSRF validation will fail for |
| 30 | +them because the expected token is stored in their session and different |
| 31 | +for each user. |
| 32 | + |
| 33 | +How to Cache Most of the Page and still Be Able to Use CSRF Protection |
| 34 | +---------------------------------------------------------------------- |
| 35 | + |
| 36 | +To cache a page that contains a CSRF token you can use more advanced caching |
| 37 | +techniques like `ESI`_ fragments, having a TTL for the full page and embedding |
| 38 | +the form inside an ESI tag with no cache at all. |
| 39 | + |
| 40 | +Another option to be able to cache that heavy page would be loading the form |
| 41 | +via an uncached AJAX request but cache the rest of the HTML response. |
| 42 | + |
| 43 | +Or you can even load just the CSRF token with an AJAX request and replace the |
| 44 | +form field value with it. |
| 45 | + |
| 46 | +.. _`Cross-site request forgery`: http://en.wikipedia.org/wiki/Cross-site_request_forgery |
| 47 | +.. _`ESI`: http://www.w3.org/TR/esi-lang |
| 48 | +.. _`Security CSRF Component`: https://github.com./symfony/security-csrf |
0 commit comments