Where developers come to connect, share, build and be inspired.

2

Forms, CSRF authenticity token and fragment caching in Rails

6615 views


Problem

You have a fragment cache like the following:

-cache ['v2', user.username, signed_in?, viewing_self?] do
  %li 
    = user.endorsements.count
    endorsements
  - user.works.each do |work|
    %li.work = work.title
    %li.endorse
      = form_tag(user_endorsements_path(@user)) do
        = hidden_field_tag :endorsed_work, work
        = link_to 'endorse', user_endorsements_path(user)

When the above haml code is compiled, rails inserts a unique csrf authenticity token (session based) in the form so when you submit it, it can rule out cross-site forgery attempts.

<form accept-charset="UTF-8" action="/users/6522/endorsements" method="post">

<div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓">

<input name="authenticity_token" type="hidden" value="VY13wlC2rgGccbkxyvm7Z1WX4LKH+71vzIj+8Um0QO8="></div>
...
</form>

However, when your form is inside a cache fragment, as the example above demonstrates, the first time the html fragment is cached the authenticity token is part of it. Now if your sessions expires and you login again, you will be served the cache fragment that contains the original csrf authenticity token value and if you try to submit the form rails will end session(log you out) and return a

403 Forbidden

or

405 Method Not Allowed

error.

Solution

A simple solution is to put the following code in your application.js file so it replaces all authenticity tokens on a page with the default one in the header:

 meta content="authenticity_token" name="csrf-param" />

 meta content="VY13wlC2rgGccbkxyvm7Z1WX4LKH+71vzIj+8Um0QO8=" name="csrf-token" />

in application.js put(JQuery version):

  $('input[name=authenticity_token]').val($('meta[name=csrf-token]').attr('content'))

now all old csrf tokens in the cache fragments will be replaced by the correct value from the current session

Comments

  • 144314100b686db946ff68c7ae1065d1

    What if you want to do page/action caching?

  • 4c64dd1fc1e50d91b712f73cfb77a7aa

    This just made my day, thanks!

Add a comment