Protecting controller actions from CSRF attacks by ensuring that all forms
are coming from the current web application, not a forged link from another
site, is done by embedding a token based on a random string stored in the
session (which an attacker wouldn‘t know) in all forms and Ajax
requests generated by Rails and then
verifying the authenticity of that token in the controller. Only
HTML/JavaScript requests are checked, so this will not protect your XML API
(presumably you‘ll have a different authentication scheme there
anyway). Also, GET requests are not protected as these should be idempotent
anyway.
This is turned on with the protect_from_forgery method,
which will check the token and raise an
ActionController::InvalidAuthenticityToken if it doesn‘t match what
was expected. You can customize the error message in production by editing
public/422.html. A call to this method in ApplicationController is
generated by default in post-Rails 2.0
applications.
The token parameter is named authenticity_token by default. If you
are generating an HTML form manually (without the use of Rails’ form_for,
form_tag or other helpers), you have to include a hidden field
named like that and set its value to what is returned by
form_authenticity_token. Same applies to manually constructed Ajax
requests. To make the token available through a global variable to scripts
on a certain page, you could add something like this to a view:
<%= javascript_tag "window._token = '#{form_authenticity_token}'" %>
Request forgery protection is disabled by default in test environment. If
you are upgrading from Rails 1.x, add this
to config/environments/test.rb:
# Disable request forgery protection in test environment
config.action_controller.allow_forgery_protection = false
Learn more about CSRF (Cross-Site Request Forgery) attacks
Here are some resources:
Keep in mind, this is NOT a silver-bullet, plug ‘n’ play, warm
security blanket for your rails application. There are a few guidelines you
should follow:
- Keep your GET requests safe and idempotent. More reading material:
- Make sure the session cookies that Rails
creates are non-persistent. Check in Firefox and look for "Expires: at
end of session"