May 10, 2012
CSRF stands for Cross-site request forgery. It is a technique hackers use to hack into a web application.
Unlike XSS CSRF does not try to steal your information to log into the system. CSRF assumes that you are already 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.
<img src="http://www.mysite.com/grant_access?user_id=1&project_id=123" />
I know you are thinking 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>
var url = "http://mysite.com/grant_access?user_id=1&project_id=123";
document.write("<form name=hack method=post action=" + url + "></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 authenticity_token
.
If you look at source code of any form generated by Rails you will see that form contains following code
<input name="authenticity_token"
type="hidden"
value="LhT7dqqRByvOhJJ56BsPb7jJ2p24hxNu6ZuJA+8l+YA=" />
The exact value of the authenticity_token will be different for you. When form
is submitted then authentication_token is submitted and
Rails checks
the authenticity_token
and only when it is verified the request is passed
along 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
That line protect_from_forgery
checks for the authentication of the incoming
request.
Here is code that is responsible for generating csrf_token
.
# Sets the token value for the current session.
def form_authenticity_token
session[:_csrf_token] ||= SecureRandom.base64(32)
end
Since this 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 POST
, PUT
and
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.
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 :exception
to :null_session
.
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.
If this blog was helpful, check out our full blog archive.