“What’s New in Edge Rails: Better Cross-Site Request Forging Prevention”

Hot on the heels of the in-depth look at Rails security options comes the addition of the CsrfKiller plugin into rails core.

The CsrfKiller plugin adds a unique session token field to all forms
that is checked on every non-GET request. This ensures that the request
received is in fact coming from the session of the authorized user
(check out wikipedia’s CSRF article if you need more details on the technique).

All you need to do to enable this protection is to add a protect_from_forgery statement in your controller that takes the familiar :except or :only option along with salt to use when generating the unique token:

And now this is the default functionality. No need to specify anything if you want the default behavior. You can still override as in the following examples, however.

class PostsController < ApplicationController protect_from_forgery :secret => ‘2kdjnaLI8’, :only => [:update, :delete, :create] …end

If you’re already using edge Rails’ default cookie session store then you don’t have to specify the :secret key.

protect_from_forgery :only => [:update, :delete, :create]

If you’re not on a cookie session store you can also change the digest
method used to generate the unique token (the default is ‘SHA1’).

protect_from_forgery :secret => 2kaienna9ea90djnaLI8, :digest => MD5

If a request comes in that doesn’t match the request forgery protection token for the current session then an ActionController::InvalidAuthenticityToken exception will be thrown. Perhaps a good place to try out the new exception handling syntax ?
Caveats: The request forgery protection only kicks in in the following scenarios:

  • Non-GET requests, so make sure the only requests that modify state are your PUT/POST/DELETE
  • On html and ajax requests. Override verifiable_request_format? if you want to expand that requests.

And what to do if you want to disable CSRF protection? Just add this to whatever controllers you don’t want to be affected:

skip_before_filter :verify_authenticity_token

And if you want to disable this site-wide, just add this to application.rb:

self.allow_forgery_protection = false