---
title: "CSRF and Rails"
description:
  "Cross site request forgery attacks are common. Rails has mechanisms to
  protect applications from such attacks. This blog discusses how Rails provides
  those mechansisms."
canonical_url: "https://www.bigbinary.com/blog/csrf-and-rails"
markdown_url: "https://www.bigbinary.com/blog/csrf-and-rails.md"
---

# CSRF and Rails

Cross site request forgery attacks are common. Rails has mechanisms to protect
applications from such attacks. This blog discusses how Rails provides those
mechansisms.

- Author: Neeraj Singh
- Published: May 10, 2012
- Categories: Rails

CSRF stands for **Cross-site request forgery**. It is a technique hackers use to
hack into a web application.

Unlike [XSS](xss-and-rails) 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.

- 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 gardening.
- 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 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

```html
<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.

## Prevention

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

```plaintext
<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](https://github.com/rails/rails/blob/6843cf6a94ae1efad0464381408a1c5f2f157376/actionpack/lib/action_controller/metal/request_forgery_protection.rb)
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.

```ruby
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`.

```ruby
# 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.

## Update for Rails 4

If you generate a brand new Rails application using Rails 4 then the
`application_controller.rb` would look like this

```ruby
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.

## Links

- [Human page](https://www.bigbinary.com/blog/csrf-and-rails)
