CSRF token and HTTP cache

Showing 1-9 of 9 messages
CSRF token and HTTP cache Grégoire Marchal 8/28/12 12:41 AM
Hi,

I have a blog project powered by Symfony 2.1.0-DEV. I use the HTTP cache to store my post pages using the modification date as "Last-Modified" header, with the public cache control header, so the cache is shared between the users (my reverse proxy is Symfony2). On those pages, there's a form that allows users to add comments about the post.

The cache works fine, the page is stored and refresh when needed, but when a user tries to add a comment, he gets this message: "The CSRF token is invalid. Please try to resubmit the form". That's normal, since the form is cached too, so the CSRF token value too.

So what is the best practice for this case?

- Set the cache control as private? It should work, until the user stores the page in cache, and comes back 2 days after: the page will be cached, but the CSRF token won't be valid anymore...
- Remove the CSRF token for this form? It bothers me to remove some security for technical reasons...
- Remove the caching for those pages? It bothers me to remove performance for technical reasons...

Do you have any other idea?

Thanks,
Grégoire.
Re: CSRF token and HTTP cache Grégoire Marchal 8/28/12 1:28 AM
I've just thought about a good workaround for that case: load the comment form on demand, using AJAX.
The page stays in cache, I just replace the form by a link that loads the form using AJAX, with no cache.
I'll try that...
Re: CSRF token and HTTP cache leonardo 8/28/12 3:57 AM
I think you can solve with ESI
http://symfony.com/doc/current/book/http_cache.html#using-edge-side-includes

Your solution is javascript intrusive ;)

ciao
Leonardo
Re: CSRF token and HTTP cache Grégoire Marchal 8/28/12 5:37 AM
I've just tried with ESI: it doesn't work.
My controller sees that the cache is up to date, so it returns a 304 "Not-Modified" header. So the template is not parsed, and my ESI is not executed. The whole page is cached, so I still have my problem.

I don't know if it's the expected behavior or if it's a bug...
Re: CSRF token and HTTP cache Christophe L 8/28/12 7:38 AM
Hello,

Maybe this approach could help you
http://www.dinduks.com/symfony-2-render-helper-for-calling-an-action-from-a-view/

i.e. rendering the action display your form has a sub-request, so it is not related to the main action/request, and so the form is not cached.

Best regards,
Christophe
Re: CSRF token and HTTP cache Artem Lopata 8/28/12 7:39 AM
It seems you are doing something wrong there. For example in a twig template you should have:

{{ article.body }}

<div id="comments">
{% render 'NamespaceCommentBundle:Comment:form' , {'standalone': true} %}
{# render your comments here #}
</div>

And in NamespaceCommentBundle/Controller/Comment you should have formAction which is not cacheable, so any hit on this will be rendered again and again and again. This way your page will just render a form and take whole page from cache. But be sure you will not send last-modified headers to client, as he will cache that page and will not get back to your server for new CSRF token.
Re: CSRF token and HTTP cache Grégoire Marchal 8/28/12 8:36 AM
@Artem Lopata: when you say "be sure you will not send last-modified headers to client", you mean for formAction, or for the whole page?

If you mean for formAction, it's already what I'm doing, there's no cache for this action.
If you mean for the whole page, that means that there's no cache at all for the page.

@Christophe L: that's what I'm doing
Re: CSRF token and HTTP cache leonardo 8/28/12 9:38 AM
For me, with sf2.1 it works
https://gist.github.com/3500049
Re: CSRF token and HTTP cache Grégoire Marchal 8/29/12 12:34 AM
Indeed, it works when I use the same cache strategy as in your gist (@Cache(smaxage="600")).
But if I replace this annotation by this code, it doesn't work anymore: https://gist.github.com/3508003