Monday, January 28, 2008

Rails Forgery Protection (CSRF) and Ajax

Rails 2.0 has forgery protection against CSRF attacks built in. If you stick to standard rails helpers you won't need to take any extra steps and the forgery protection will just work - reason being, the helpers will automatically add the appropriate parameters. For example form helpers will a hidden tag with the name "form_authenticity_token" and a value "big stinking authenticity token."

If you step into the land of raw Ajax, however, you will need to take care of passing this value yourself (unless you are sending GET requests, you don't need to send the token with a GET request). So where do you get the value? You use the helper form_authenticity_token of course. But I don't recommend using this value directly as it can throw and exception if you call it with forgery protection turned off (in tests for example). Instead, write your own helper in app/helpers/application_helper.rb, something like this:



Now in your view you can write the value where you need it or you can store the value in a javascript variable for later use:



Now when you make an Ajax request you just need to make sure you provide this value under the name "authenticity_token". For prototype.js, you can stuff this along in the options to the family of Ajax request functions:



If you are using the amazing Ext JS, you might send it along with something like this:



Oh, also, if you want to turn off this forgery protection you can remove it entirely by commenting out protect_from_forgery in your main application.rb controller or disable / enable it on an action by action basis in a controller with:



And of course that takes either an :except or :only value.

6 comments:

  1. Thanks a lot!
    It really helps me.

    ReplyDelete
  2. Many thanks for this. I was beating my head against a brick wall - nice to have it clearly explained.

    ReplyDelete
  3. btw, shouldn't protect_from_forgery? be protect_against_forgery?

    ReplyDelete
  4. Ah yes, Martin Hawkins, you are correct that should be protect_against_forgery?. I will fix the post. Thanks.

    ReplyDelete
  5. Maybe this is new, but the method shown in protect_from_forgery document in Rails 2.3 shows this for controlling csrf on a controller-by-controller basis:

    # you can disable csrf protection on controller-by-controller basis:
    skip_before_filter :verify_authenticity_token

    The :only and :except options seem to be respected:

    skip_before_filter :verify_authenticity_token, :only => [:action_one, :action_two]

    ReplyDelete
  6. I have wrote plugin that does this automatically. All you have to do is add <%= remote_forgery_protection %> inside head section of your layout.
    For now Prototype, jQuery and ExtJS are supported.

    http://github.com/vlado/remote_forgery_protection

    ReplyDelete