Ruby on Rails Security Basics

Category: Web Security Readings - Last Updated: Tue, 06 Dec 2016 - by Ryan Dewhurst

Recently I have been working on my first Rails application, even though I have been working with Ruby for a number of years, this is the first time I've ever developed an application using the Rails framework. By trade, I'm a Security Tester, however, I do like to work on software projects in order to keep my skills sharp and practice what I preach.

Rails has some security features built in and enabled by default, however, I also recommend installing some additional Gems which cover security features Rails lacks by default. This article explains what are the basic Ruby on Rails built in security features and which are the gems I recommend intsalling.

Ruby on Rails Built in Security Features

I'm a great believer in secure by default and making security easy for developers. Some may argue that by making security easy, it will make developers pay less attention to security and possibly lead them to making more security mistakes. Kind of like a horse with blinkers on. In reality I think it is probably a balance, don't make security invisible to the developer but instead make it just easy enough for them to implement correctly.

So be warned! Don't just rely on Rail's built in security features thinking that they offer a 100% effective way at mitigating the vulnerabilities they were designed to prevent against. Instead, learn how to use them correctly and know their limitations.

Preventing Cross-Site Scripting (XSS)

To help prevent Cross-Site Scripting (XSS) vulnerabilities we sanitise input and encode output using the correct encoding for the output context.

Sanitising Input

Rails makes sanitising input easy with its Model View Controller (MVC) design. Any data stored or retrieved from a database should pass through a Model, so this is a great place to sanitise our stored data. Using Active Record Validations within our models we can ensure that data is present and/or in a specific format.

You can also sanitise input/output within your View using the sanitize method. The sanitize method 'will html encode all tags and strip all attributes that aren't specifically allowed'. Let's pass it a common XSS payload and see how it reacts:

<%= sanitize '<img src=x onerror=prompt(1)>' %>

The above will output:

<img src="x">

As we can see the sanitize method has allowed our img tag with the src attribute, but it has  removed the onerror event attribute. By default, if we don't whitelist which tags/attributes we want, Rails will make that decision for us on what it believes is 'safe'.

If we whitelist the src and onerror attributes, our XSS payload is executed:

<%= sanitize '<img src=x onerror=prompt(1)>', attributes: %w(src onerror) %>

The above will output:

<img src="x" onerror="prompt(1)">

Encoding Output

In modern versions of Rails, strings output in the View are automatically encoded. However, there may be occasions when you want to encode HTML output by yourself. The main output encoding method in rails is called html_escape, you can also use h() as an alias. The html_escape method 'escapes html tag characters'.

Let's pass it a common XSS payload and see how it reacts:

<%= html_escape '<img src=x onerror=prompt(1)>' %>

The above will output:

&lt;img src=x onerror=prompt(1)&gt;

As we can see the html_escape method has converted the < and > characters into html entities, ensuring the browser does not interpret them as markup.

This is the same output as we would see if we simply passed a string, thanks to Rails's default encoding:

<%= "<img src=x onerror=prompt(1)>" %>

The above will output:

&lt;img src=x onerror=prompt(1)&gt;

But don't forget what we said earlier! Just because modern versions of Rails encode strings in Views by default, does not mean that XSS can not happen. One example is within the href value of a link (using the link_to method).

Preventing Cross-Site Request Forgery (CSRF)

Modern versions of Rails protect against CSRF attacks by default by including a token named authenticity_token within HTML responses. This token is also stored within the user's session cookie - when a request is received by Rails it checks one against the other. If they do not match, an error is raised.

It is important to note that Rails's CSRF protection does not apply to GET requests. GET requests should not be used to change the application's state anyway and should only be used to request resources.

Although enabled by default, you can double check that it's enabled by seeing if the protect_from_forgery method is within the main ApplicationController.

Preventing SQL Injection

Rails uses an Object Relational Mapping (ORM) framework called ActiveRecord to abstract interactions with a database. ActiveRecord, in most cases, protects against SQL Injection by default, however, there are ways in which it can be used insecurely which can lead to SQL Injection.

Using ActiveRecord we can select the user with the supplied id and retrieve that user's username:


The above will return the username of the user whose user id matches the one supplied via the params hash. Let's take a look at the SQL query generated by the code above on the backend:

SELECT  "users".* FROM "users"  WHERE "users"."id" = ? LIMIT 1  [["id", 1]]

As we can see from the SQL query above, when using the find method on the User object ActiveRecord is binding id to the SQL statement. Protecting us from SQL Injection.

What if we wanted to select a user which matched a username and password, commonly seen in authentication forms. You might see something like this:

User.where("username = '#{username}' AND encrypted_password = '#{password}'").first

If we supply a username with the value ') OR 1-- the corresponding SQL query on the backend becomes:

SELECT  "users".* FROM "users"  WHERE (username = '') OR 1--' AND encrypted_password = 'a')  ORDER BY "users"."id" ASC LIMIT 1

By injecting our specially crafted SQL, what we have done is told the database to return all rows from the users table where the username is null or true. This makes the SQL statement return true along with all of the data in the users table.

For some great examples of how not to use ActiveRecord, here's a great resource which I suggest you check regularly to ensure you don't have any of the examples within your code -

Ruby on Rails Security Gems

As we have seen, Rails offers many built in security features to help protect our applications, data and users from web based attacks. But we also saw that these have their limitations. For security features that Rails does not offer by default there are always Gems, lots and lots of Gems. Here are some of my favourite.


Devise is a popular authentication and authorisation Gem for Rails. It offers secure password storage using bcrypt to hash salted passwords. User lockouts, user registration, forgot password functionality and more.

Although Devise's own README states "If you are building your first Rails application, we recommend you to not use Devise", I would ignore this statement. If you're security aware and have built applications in other frameworks before, I don't see any issue with using Devise for your first Rails application.



Brakeman is a Static Code Analysis tool for Rails applications. It searches your application's source code for potential vulnerabilities. Although it does report the occasional False Positive, personally, I think this is a great Gem and one I would definitely recommend running against your application before going into production. Even better, run it after every commit.



Developed by Twitter, SecureHeaders is a Gem that implements security related HTTP headers into your application's HTTP responses. Headers such as Content Security Policy to help protect against Cross-Site Scripting (XSS) attacks, HTTP Strict Transport Security (HSTS) to ensure your site is only accessible over secure HTTPS, X-Frame-Options and others.



Developed by Kickstarter, Rack::Attack is a Gem for blocking & throttling abusive requests.   Personally, I use Rack::Attack to prevent forms being abused, for example, instead of implementing a CAPTCHA on a submission form, I use Rack::Attack to ensure it is not submitted too many times in a short space of time. This should prevent automated tools from abusing the form submission. It also supports whitelisting and blacklisting of requests.



Codesake::Dawn is similar to brakeman in that it scans your source code for potential vulnerabilities. However, Codesake::Dawn also has a database of known vulnerabilities which it uses to scan your Ruby, Rails and Gems for known issues.


Ruby on Rails Code Quality Gems

Sloppy and messy code leads to bugs and some bugs may have security implications. Better quality code is more secure code. Let's take a look at what Gems we can use to ensure our code is nice and clean.


The rails_best_practices Gem is a great Gem for ensuring your code is adhering to best practices. It will help you make your code more readable and eloquent by scanning through it and giving you suggestions on how to improve the syntax.



Rubocop is not specific to Rails and can be used for any Ruby application. It uses the Ruby Style Guide as a reference to scan your code and ensure you adhere to it. Things like variable naming, method size, using outdated syntax, etc.



Rails does a lot of things right when it comes to security. When developing a Rails application it feels like Rails has your back. However, don't let this sense of security lull you into a state of not caring about security. As we have seen, there are pitfalls, and it only takes one mistake for your users table to end up pastebin.

No post on the Netsparker blog would be complete without a Netsparker plug. Everything we've talked about in this post is mostly source code related. As well as looking at your application's source code, you should also ensure it is scanned with a heuristic scanner like Netsparker. You can take every development precaution, read every line of code, but this does not mean you will catch every single vulnerability. Netsparker web vulnerability scanner should be used in conjunction with what has been discussed above throughout your Security Development Lifecycle, as well as when in production.

Further Reading

Below is a list of URLs from where you can find more information about Ruby on Rails security and best coding practices.


Dead accurate, fast & easy-to-use Web Application Security Scanner