Putting form_authenticity_token (csrf token) in a cookie instead of in meta tags?

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

<%= csrf_meta_tags %>

``

It does this so the remote forms can be submitted–i.e., so JavaScript can submit a form. When jquery-rails is about to submit a form, it looks for the tags named “csrf-param” and “csrf-token” and from them it constructs a hidden “authenticity_token” param from it. It gets inserted in with the POST data so Rails will accept the request.

I would like to 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.

I have an idea for how to fix it but thought I would ask here, to see if people think there would be problems with it: I could create an after_action in ApplicationController that looks like this:

after_action :set_authenticity_cookie

def set_authenticity_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, I could write a little JavaScript that pulls it out of the cookie and dynamically creates the meta tags that jquery-rails is expecting.

Questions:

  1. Does this expose me to any security problems?
  2. Is there any reason this wouldn’t work?

Thanks,

Brian

I’ll answer the second question first. I’m not sure the form_authenticity_token will persist. It might. If not, you can use (and probably should use) session[:_csrf_token]. Otherwise, I haven’t tested it, but it seems like it should work.

The first question is probably the bigger concern. The purpose of cross site request forgery is to insure that requests originate from the application. It seems your javascript would circumvent that by inserting the token in the form. What event will trigger your javascript? Will any form that gets submitted, regardless of its origin? If so, IMO, you have a significant security risk. In other words, how will you insure that only forms obtained from your Varnish server or the application get submitted and everything else will be rejected?