CSRF and Rails
CSRF stands for Cross-site request forgery. It is a technique which hackers might use to hack into a web application.
Unlike XSS CSRF does not try to steal your informationt to log into the system. CSRF assumes that you are aleady logged in at your site. And when you visit say comments section of some other site then an attack is done on your site without you knowing it.
Here is how it might work.
- You log in at www.mysite.com .
- Now you open a new tab and you are visiting www.gardening.com since you are interested in gardeing.
- You are browsing the comments posted on the gardening.com forum. One of the comments posted has url which has source like this
<img src="http://www.mysite.com/grant_access?user_id=1&project_id=123" />
- Now if you are the admin of the project “123” in www.mysite.com then unknowingly you have granted admin access to user 1. And you did not even know that you did that.
I know. You are thiniking that loading an image will make a
GET request and granting access is hidden behind
POST request. So you are safe. Well the hacker can easily change code to make a
POST request. In that case the code might look like this
<script> document.write('<form name=hack method=post action="http://mysite.com/grant_access?user_id=1&project_id=123"></form>') </script> <img src='' onLoad="document.hack.submit()" />
Now when the image is loaded then a
POST request is sent to the server and the application might grant access to this new user. Not good.
In order to prevent such things from happening Rails uses
If you look at source code of any form generated through Rails scaffolding you will see that form markup contains following code
<input name="authenticity_token" type="hidden" value="LhT7dqqRByvOhJJ56BsPb7jJ2p24hxNu6ZuJA+8l+YA=" />.
The exact value of the authenticity_token will be different. When form is submitted then Rails checks the authenticity_token and only when it is verified the request is sent for further processing.
In a brand new rails application the
application_controller.rb has only one line.
class ApplicationController < ActionController::Base protect_from_forgery end
protect_from_forgery checks for the authentication of the incoming request.
Here is code that is responsible for generating
# Sets the token value for the current session. def form_authenticity_token session[:_csrf_token] ||= SecureRandom.base64(32) end
csrf_token is a random value there is no way for hacker to know what the “csrf_token” is for my session. And hacker will not be able to pass the correct “authenticity_token”.
Do keep in mind that this protection is applied only to
DELETE requests by Rails. Rails states that
GET should not be changing database in the first place so no need for check for authenticity of the token.
Update for Rails4
If you generate a brand new Rails application using Rails 4 then the
application_controller.rb would look like this
class ApplicationController < ActionController::Base # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception end
Now the default value is to raise an exception if the token is not matched. The API calls will not have the token. If the application is expecting api calls then the strategy should be changed from
Note that if the site is vulnerable to XSS then the hacker submits request as if he is logged in and in that case the CSRF attack will go through.