From 7226f6cecfb00f18e851b7081c4f3d711803934a Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Sat, 12 Jan 2019 17:47:30 +0100 Subject: [PATCH 1/5] Add documentation to overwrite token widget block using esi --- http_cache/form_csrf_caching.rst | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/http_cache/form_csrf_caching.rst b/http_cache/form_csrf_caching.rst index 41aba4c0eab..9321b76234a 100644 --- a/http_cache/form_csrf_caching.rst +++ b/http_cache/form_csrf_caching.rst @@ -30,7 +30,32 @@ 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 :doc:`ESI fragments `, where you cache the full -page and embedding the form inside an ESI tag with no cache at all. +page and embedding the form inside an ESI tag with no cache at all. When you +have your custom form theme you can do this by create a new token_widget block +and call render_esi there: + +.. code-block:: twig + + {%- block token_widget %} + {{ render_esi(controller('App\\Controller\\FormController::token', { 'form': form.parent.vars.name })) }} + {%- endblock token_widget -%} + +You can use the ``security.csrf.token_manager`` service to generate a token for your given form: + +.. code-block:: php + + public function token(Request $request, TokenGeneratorInterface $generator) + { + $formName = $request->attributes->get('form'); + $csrfToken = $csrfTokenManager->getToken($formName)->getValue(); + + return new Response(sprintf( + '', + $formName, + $formName, + $csrfToken + )); + } Another option would be to load the form via an uncached AJAX request, but cache the rest of the HTML response. @@ -39,5 +64,7 @@ Or you can even load just the CSRF token with an AJAX request and replace the form field value with it. Take a look at :doc:`hinclude.js ` for a nice solution. + + .. _`Cross-site request forgery`: http://en.wikipedia.org/wiki/Cross-site_request_forgery .. _`Security CSRF Component`: https://github.com/symfony/security-csrf From 73c888d75019b2fe06d0664507a6c25fae62f5f6 Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Sat, 12 Jan 2019 17:54:57 +0100 Subject: [PATCH 2/5] Fix typo in documentation of esi csrf token --- http_cache/form_csrf_caching.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/http_cache/form_csrf_caching.rst b/http_cache/form_csrf_caching.rst index 9321b76234a..972e6783f31 100644 --- a/http_cache/form_csrf_caching.rst +++ b/http_cache/form_csrf_caching.rst @@ -30,9 +30,9 @@ 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 :doc:`ESI fragments `, where you cache the full -page and embedding the form inside an ESI tag with no cache at all. When you -have your custom form theme you can do this by create a new token_widget block -and call render_esi there: +page and embedding the form or just the CSRF token inside an ESI tag with no +cache at all. When you have your custom form theme you can do this by create a +new token_widget block and call render_esi there: .. code-block:: twig From 9e356b7b61b6effe0302731f416aa7bb8ca4ec86 Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Sat, 12 Jan 2019 17:55:14 +0100 Subject: [PATCH 3/5] Fix typo in doc --- http_cache/form_csrf_caching.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/http_cache/form_csrf_caching.rst b/http_cache/form_csrf_caching.rst index 972e6783f31..a30dce4623e 100644 --- a/http_cache/form_csrf_caching.rst +++ b/http_cache/form_csrf_caching.rst @@ -64,7 +64,5 @@ Or you can even load just the CSRF token with an AJAX request and replace the form field value with it. Take a look at :doc:`hinclude.js ` for a nice solution. - - .. _`Cross-site request forgery`: http://en.wikipedia.org/wiki/Cross-site_request_forgery .. _`Security CSRF Component`: https://github.com/symfony/security-csrf From 0ea3b52b33fd7a2d29350af05b361a2c123ac4a9 Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Sat, 12 Jan 2019 18:49:50 +0100 Subject: [PATCH 4/5] Add cache headers to rexample --- http_cache/form_csrf_caching.rst | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/http_cache/form_csrf_caching.rst b/http_cache/form_csrf_caching.rst index a30dce4623e..0843d42f4ea 100644 --- a/http_cache/form_csrf_caching.rst +++ b/http_cache/form_csrf_caching.rst @@ -49,12 +49,22 @@ You can use the ``security.csrf.token_manager`` service to generate a token for $formName = $request->attributes->get('form'); $csrfToken = $csrfTokenManager->getToken($formName)->getValue(); - return new Response(sprintf( + $response = new Response(sprintf( '', $formName, $formName, $csrfToken )); + + // Make sure the response is not cached + $response->setPrivate(); + $response->setSharedMaxAge(0); + $response->setMaxAge(0); + $response->headers->addCacheControlDirective('must-revalidate', true); + $response->headers->addCacheControlDirective('no-cache', true); + $response->headers->addCacheControlDirective('no-store', true); + + return $response; } Another option would be to load the form via an uncached AJAX request, but From 0c43acbcf6bb3c64d7a78d8baac1371c6ede1a29 Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Sat, 12 Jan 2019 18:53:02 +0100 Subject: [PATCH 5/5] Add some text to avoid response caching --- http_cache/form_csrf_caching.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/http_cache/form_csrf_caching.rst b/http_cache/form_csrf_caching.rst index 0843d42f4ea..abea53b988d 100644 --- a/http_cache/form_csrf_caching.rst +++ b/http_cache/form_csrf_caching.rst @@ -56,7 +56,9 @@ You can use the ``security.csrf.token_manager`` service to generate a token for $csrfToken )); - // Make sure the response is not cached + // In some cases you have a response listener maybe which will set cache headers + // automatically most kind of this listener will not set it if cache headers exist + // so add the following if you want to be sure the response is not cached: $response->setPrivate(); $response->setSharedMaxAge(0); $response->setMaxAge(0);