TechEnthu

How does rails handle CSRF attacks using CSRF token…?

CSRF Stands for Cross Site Request Forgery. First of all, let us know what is a CSRF attack and how it happens? Then we shall use how rails would prevent CSRF?

What is CSRF attack and how it’s executed well…?

That tricks a web browser into executing an unwanted action in an application to which a user is logged in. Say, you are browsing your bank details. The GET request for transferring money to PersonA would be

 GET http://mybank.com/transfer.do?acct=PersonA&amount;=$100 HTTP/1.1

The attacker studies the application thoroughly where he could manipulate actions of the users. When you’re logged in into your bank application, the attacker sends link or image through email which could point to a GET request. So upon clicking the link or on image, the user action gets manipulated in the application. The GET request may look like this.

 <a href="http://www.mybank.com/transfer_money?user_id=123&amount=1000000"> View my Pictures! /a>

would execute the below request.

 GET http://mybank.com/transfer.do?acct=AttackerB&amount;=$100000 HTTP/1.1 

A successful CSRF attack can be devastating for both the business and user. It can result in damaged client relationships, unauthorised fund transfers, changed passwords and data theft—including stolen session cookies.

The POST request can be triggered using form tag by the attacker.


<body onload="document.forms.submit()">
   <form action="http://mybank.com/transfer.do" method="POST">
     <input type="hidden" name="acct" value="AttackerA"/>
     <input type="hidden" name="amount" value="$10000"/>
     <input type="submit" value="View my pictures!"/>
   </form>
</body>

Rails using CSRF token preventing attacks

Rails uses CSRF token which ensures that the request is coming from the application. When making a POST request using the form, the authenticity token also is sent with the parameters whereby checking the token stored in user session. If user session token matches the authenticity token then the POST request is said to proceed, otherwise rails raises an ActionController::InvalidAuthenticityToken exception.


# Sets the token value for the current session.
def form_authenticity_token
  session[:_csrf_token] ||= SecureRandom.base64(32)
end

The token will be added automatically to every form like this:

 <input name="authenticity_token" type="hidden" value="OXuQV+9Q1hi5YkeynLQgVddCRfdUwl0huvqSjoqf4mE=" />.

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.

Security check for APIs

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.

So, for APIs we need to have a authentication token for accessing the APIs. CSRF token should not work in case of application expecting API calls. The authentication token is generated when a user enters a required credentials, say like username, password, user_access_secret or user_access_key etc., Make sure that GET requests does not execute insert, update or delete queries in the DB.

In rails 5

class ApplicationController < ActionController::Base
  protect_from_forgery
end

In rails 4

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