Preventing CSRF Vulnerabilities in Rails: What You Need to Know

Preventing CSRF vulnerabilities in Rails is a crucial aspect of maintaining a secure and robust platform for developers. Rails, renowned for its vibrant community and extensive documentation, offers a mature platform that requires rigorous security measures. One of the security concerns that Rails developers often face is cross-site request forgery, also known as CSRF or XSRF.

You may be considering how to keep your Rails application secure and immune to potential threats, including CSRF vulnerabilities. This post is geared towards informing you about CSRF vulnerabilities and providing clear-cut strategies for preventing CSRF vulnerabilities in Rails applications.

By the end of this post, you’ll have a clear understanding of what CSRF vulnerabilities are, why it’s vital to keep them in check, and how to avert potential CSRF threats in your Rails applications to secure your business.

What Is CSRF?

If you’ve never heard of CSRF, XSRF, cross-site request forgery, or any variation of what this acronym describes, let us give you a quick rundown. 

Cross-site request forgery is an attack that takes advantage of the end user’s privileges over their session. As the name suggests, the attacker sidesteps most security measures by tricking the user into submitting a forged request (GET, POST, or PUT, for example) with malicious content outside the target site. 

Most CSRF attacks exploit the user’s inability to discern if a harmless element contains malicious code. Bad actors mask these elements using social engineering tactics like chat or emails. These exploits come from seemingly trusted sources, hijacking the user’s trust. 

When the user clicks on one of these links, a targeted URL can execute a change in the database (email change, bank transfer, etc.) to a vulnerable web application where the user currently has a session open. This could be as simple as having a tab open with the target website while logged in. 

CSRF attacks are some of the most widespread forms of malicious exploits on the web. Web platforms are exposed to them daily, and countless unsuspecting users fall prey to their predatory tricks. 

Moreover, no platform can be entirely impervious since the attack can always hijack a valid end user’s authentication to reach the system. We can’t close all the doors of access without taking away convenience from a valid end user. 

For this reason, we must ensure that we, as developers, take all measures necessary to reduce the avenues of attack. 

Examples of Attacks

You might be wondering what a CSRF attack looks like in the wild. Well, let’s explore some examples. 

The Horny Fish

An unsuspecting bank account user receives an email from a seemingly trusted party while they have an open session in the browser. 

Rails CSRF Attack

Well, this seems innocent enough. Let’s take a closer look at that link. 

Rails CSRF Attack 2

Uh-oh! That’s a no-no. 

As you can see, average users seldom bother to check the actual URL of a hyperlink—regardless of its origin. Unfortunately, this makes them easy targets for this kind of attack. 

These exploits are widespread in phishing attacks and more sophisticated social engineering attacks. Even the most trained engineers can fall victim to simple attacks like this.

The Curious Seller

In a similar situation, a sales representative of some company receives an email at work — while their system tools open — with an attractive headline and promise of reward. 

CSRF Vulnerabilities in Rails

That seems legitimate. Let’s check it out. 

CSRF Vulnerabilities in Rails

Our victim sees this email, and at first glance, it seems legitimate. However, they click on the link only to see a blank screen.

Wait, where’s the content? What happened? 

It might seem like this is a case of “Oops! The CRM system sent an invalid link to a broken page.” However, once you start checking things like the sender’s email address, this seemingly trustworthy email starts falling apart on close examination. 

Let’s check what’s under the hood. 

Preventing CSRF Vulnerabilities in Rails

No! Roxxx strikes again! And this time, the victim didn’t even see it coming. 

This exploit is especially concerning because the attacker could be targeting administrative users and cause significant harm to a business and its infrastructure with a little more sophistication. 

Preventing CSRF Vulnerabilities in Rails

All right, we’ve seen how creative attackers can find ways to exploit other people’s valid sessions by hiding their malicious code in harmless-looking elements and inviting users to trigger an action. And all this is done by hijacking people’s trust with sly social engineering tactics. 

CSRF Vulnerabilities
Photo by sebastiaan stam on Unsplash

So, how can we protect our systems and users from these exploits? 

We can mitigate the risk of exploitation from the platform perspective in several ways. Let’s go through them in the context of a Rails website. 

Routing Structure

First, we need to reevaluate how we design the routing structure of our website. The first attack was successful because the system accepted a state-changing action with a GET request. Unfortunately, this structure is already a bad practice that should be avoided even outside the scope of security. 

To fix this, change the route file and set the application’s action to accept a POST, PUT, or any other protocol depending on the type of action that will be performed. 

Rails.application.routes.draw do    
    root' home#index'    
    # get 'transfer', to: 'transactions#create' # BAD    
    put 'transfer' to: 'transactions#create' # GOOD
End

However, it’s essential to note that this strategy will not protect us from the second attack since it comes from a form tag submitting a POST automatically by JavaScript. In this case, our user didn’t even get a chance to understand what was going on. 

Additionally, the attacker can adapt this kind of exploit to work with a JavaScript Ajax request and submit any protocol or parameters necessary to achieve the attacker’s goal. 

Action Confirmation

Second, implementing a confirmation mechanism into any critical state-changing action is recommended- but only sometimes necessary. This design-based security feature is generally adopted on admin systems and account management portals. 

For this fix, implement a middle step between critical actions to require the user to confirm the action to perform. 

This mechanism would typically allow the victim to have a chance to cancel a potentially malicious attack from submitting to the server. However, some users might find this multistep process cumbersome and tedious in systems that require frequent changes from the user. That’s why some systems choose to do without it. 

Origin Confirmation

Third, it goes without saying, but you must always confirm the origin of any request submitted to your server. Be it by the REFERRER info found on the request HEADER or any other method, you can use this simple tactic to weed out much potential damage.

To enable this, you can use gems like rack-cors that work as gatekeeper middleware, preventing invalid requests from being processed. 

# Gem file
gem 'rack-cors'

config/initializers/cors.rb

use Rack::Cors do
    allow do origins' localhost:3000',
        '127.0.0.1:3000',
        /\Ahttp:\/\/192\.168\.0\.\d{1,3}(:\d+)?\z/
        # regular expressions can be used here
        resource '/file/list_all/',
            headers: 'x-domain-token'
        resource'/file/at/*',
            methods: [:get, :post, :delete, :put, :patch, :options, :head],
            headers: 'x-domain-token',
            expose: ['Some-Custom-Response-Header'],
            max_age: 600
        # headers to expose
    end

    allow do origins'*'
        resource'/public/*',
            headers: :any,
            methods: :get
        # Only allow a request for a specific host
        resource '/api/v1/*',
            headers: :any,
            methods: :get,
            if: proc { |env| env['HTTP_HOST'] == 'api.example.com' }
    end
end

Incidentally, your system might require you to accept requests from origins outside your domain, which is very common. Still, you can have a set of safelisted sources the server validates and mitigate the risks. 

Rails CSRF Token

Finally, our arsenal’s most robust mitigation strategy is CSRF tokens. The server generates these tokens, links them to the user session, and stores them in the database. 

This token is then injected into any form presented to the client as a hidden field. When the client correctly submits the form for validation, it returns the token to the server. 

Rails already include this security mechanism in its ActionController module under the RequestForgeryProtection class. 

To activate it, you need to include the following line in the ApplicationController class: 

protect_from_forgery with: :null_session

You can choose what kind of action to perform when the server finds an offending request: 

  • null_session: Provides an empty session during request but doesn’t reset it completely. (This is the default action if none is specified.)
  • reset_session: Resets the session.
  • exception: Raises an ActionController::InvalidAuthenticityToken exception.

After doing this, go to your application’s base template view file, usually the Application.html.erb. Then, include this line in the header: 

<%= csrf_meta_tags %>

And that’s it. 

With this simple method, Rails’ JavaScript framework will update every form tag on the page with the generated token. Subsequently, any invalid requests arriving from outside our platform will be flagged and ignored. 

Going Beyond Preventing CSRF Vulnerabilities in Rails

Having proper security is one of those intangible values you can appreciate only when put to the test. Most managers will find it challenging to convince stakeholders of the financial investment and time needed to provide a solid level of security. 

Yet in this day and age, ever more sophisticated attacks are becoming more widespread. So, it’s difficult not to justify the investment in reassurance and peace of mind provided by adequate security measures. 

Thankfully, nowadays, modern platforms like Rails are making it more accessible and manageable to keep security standards high. That way, you can focus on what matters: bringing value to your clients. 

This post was originally written for and published by StackHawk.com


Posted

in

by

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.