form_authenticity_token (csrf meta tags) interferes with proxy caching

When you generate a default Rails app, it puts this in application.html.erb:

<%= csrf_meta_tags %>

This inserts a couple of tags in in the It does this so the remote forms can be submitted–i.e., so JavaScript can submit a form and the server knows it’s coming from a page it generated.

For public pages, it would be nice be able to serve identical HTML content for all users so the page can be cached on Varnish or a CDN or whatever. Since the form_authenticity_token is different for every session, leaving csrf_meta_tags in the header makes it impossible for a proxy to cache the page. (E.g., perhaps it’s a blog where non-logged-in users are allowed to post comments.)

I have an idea for how to fix it in Rails. I would ask here, to flesh it out and see if people think there would be problems with it. In the default-generated Rails app, we would take out the insertion of csrf_meta_tags. Instead, the ApplicationController would have an after_action that looks like this:

after_action :set_csrf_cookie

And in ActionController::Base, set_authenticity_cookie would look like this:

def set_csrf_cookie

cookies[:form_authenticity_token] = form_authenticity_token if form_authenticity_token

end

So basically send the form_authenticity_token to the browser in a cookie instead of putting it in the HTML.

Client-side, jquery-rails could have a $(document).load handler that pulls it out of the cookie instead of out of the meta tags when submitting a form.

The main problem I see with this is bootstrapping the cookie in the first place. If the user only hits pages that the proxy has cached, and never gets to the real server, he’ll never get the cookie and he won’t be able to submit any forms. Maybe someone has a clever solution to that part of the problem. Perhaps jquery-rails could be configured to go fetch the csrf token and store it in a cookie if it can’t find it.

Also, for this to work, any proxy cache would have to be configured to allow caching of pages that include cookies. (Presumably they still only cache the HTML and not the cookies, right?)

Questions:

  1. Does this expose any security problems?

  2. Is there any reason this wouldn’t work?

Thanks,

Brian