Securing your Ruby and Rails Codebase
Tags: security, ruby, rails
Published: 2018-09-24 08:09:55

---
published: true
title: Securing your Ruby and Rails Codebase
description: Using open source tools to improve the quality and security of your Ruby and Ruby on Rails applications.
cover_image: https://www.occamslabs.com/img/posts/securing_your_ruby_and_rails_codebase.png
canonical_url: https://www.occamslabs.com/blog/securing-your-ruby-and-rails-codebase
tags: security, ruby, ruby on rails
---

When writing software you want to avoid introducing functional bugs or security issues.

For functional bugs, we usually write unit tests and try to cover edge cases. Integration tests then make sure that things work together.

In this article, we will walk through how we can secure a Ruby, Rails, or Rack-based app.

No matter if it is a new codebase, or we are adding it to a 10-year-old project, in the end we will have a decent level of security testing.

For this article we will be using open-source software tools to secure our codebase. We will also consider some hosted and already configured alternatives.

**Our toolbox**:

- bundler-audit
- brakeman
- rubocop (has some security rules)

The tools can be categorized into Static Application Security Testing (SAST) and Software Composition Analysis (SCA) tools.

Static analysis scans your codebase and looks for certain kinds of patterns. It will not execute your code and cannot detect problems in generated code, or at runtime.

The results will usually show the line of code the issue is detected. They will also alert you to the type of issue identified (with a severity), and sometimes an advisory on how to fix the problem.

In contrast, software composition analysis will check the dependencies you are using for vulnerabilities.

The report usually includes:

- The package name of the affected dependency.
- Severity on how bad it is. This usually spans from `none` to `critical`.
- The next safe version to upgrade to.
- Some more references that explain what the problem is and more details.
- In some cases an identifier that leads to a vulnerability database.

To run the security tools, you do not need a CI pipeline but it is generally recommended to have one in place.

We will install the tools in a ruby/rails project. You will also learn how to enable the rake tasks and run them.

All the tools also have normal executables and can be used one by one, or in a shell script.

## Bundler Audit

[Bundler Audit](https://github.com/rubysec/bundler-audit) will detect vulnerable dependencies in your codebase

First, add the bundler-audit gem to your Gemfile:

``` shell
gem 'bundler-audit'
```

and install your bundle.

Now you can run a

``` shell
bundle audit check --update
```

This will update the local database first, and then check your project for vulnerable dependencies.

Keep in mind that `bundle audit` does not update the dependencies automatically. I recommend you to always update them before each run to ensure you get the best and most up-to-date results.

To enable the rake tasks, add the following to your project Rakefile:

``` ruby
require 'bundler/audit/task'
Bundler::Audit::Task.new
```

A `rake bundle:audit` will now update the data and perform the checks.

If you found any vulnerabilities at this point do not freak out. You can look into fixing them by updating the version to the next safe one.

In case you can not update, you can use the `--ignore $vulnerability-id` to suppress it for now.

For example:

``` shell
bundle audit check --update --ignore OSVDB-108664
```

The output looks something like this:

``` shell
$ bundle audit check --update

Updating ruby-advisory-db ...
From https://github.com/rubysec/ruby-advisory-db
 * branch            master     -> FETCH_HEAD
Already up to date.
Updated ruby-advisory-db
ruby-advisory-db: 322 advisories
Name: omniauth-oauth2
Version: 1.0.2
Advisory: CVE-2012-6134
Criticality: High
URL: http://www.osvdb.org/show/osvdb/90264
Title: Ruby on Rails omniauth-oauth2 Gem CSRF vulnerability
Solution: upgrade to >= 1.1.1

Name: rubyzip
Version: 1.2.1
Advisory: CVE-2018-1000544
Criticality: Unknown
URL: https://github.com/rubyzip/rubyzip/issues/369
Title: Directory Traversal in rubyzip
Solution: upgrade to >= 1.2.2

Vulnerabilities found!
```

## Brakeman

Next, we will add [Brakeman](https://github.com/presidentbeef/brakeman) as our first static code analysis tool.
Brakeman will look for known insecure patterns and configurations in your code base. It will also check if you are using a known vulnerable rails version.

Brakeman works not only for Rails, but it also covers Sinatra and any kind of rack application.

First, add the dependency to your Gemfile:

``` shell
gem brakeman
```

and install it:

``` shell
bundle install
```

Then you can run it for the first time in your rails root directory.

``` shell
brakeman
```

This will invoke Brakeman and output some lengthy report. Here is a gist with a sample report: https://gist.github.com/pxlpnk/4a829b6101abe5fc0102d358d8dd028d

**If your app is safe and you get no findings run it, first of all good job!**

But then you want to see how it looks like, so you can try it with [OWASP/RailsGoat](https://github.com/OWASP/railsgoat).

If you run Brakeman for the first time on any older Rails application you might get a lot of findings.

To make things easier, you want to start with more severe issues and work down to the less critical ones.

To do so, use `brakeman -w3` and it will show only high, `-w2` will show high and medium, `-w1` will show all other findings.

Approaching it level-by-level usually works the best and is the most efficient.

If you plan to use rake, you can install the RakeTask very easily.

Running a

`brakeman --rake`

will create a task file in `lib/tasks/brakeman.rake` which can be run with:

``` shell
rake brakeman:run
```

To customize it and use more advanced options see the documentation [brakeman as a library/](https://brakemanscanner.org/docs/brakeman_as_a_library/).

## RuboCop

While [rubocop](https://github.com/rubocop-hq/rubocop) is known as a linter and formatter, it comes with some security rules and can be extended with some community extensions.

Let us get started with installing RuboCop first. Add the following to your Gemfile:

``` ruby
gem 'rubocop', require: false
```

Then run our old friend

``` shell
bundle install
```

Once this has finished, you can execute the `rubocop` command.

If you have not used rubocop before you might see a lot of output and warnings printed out in your terminal.

For this post, we are not so much interested in the linting and formatting rules. Instead we make sure we only run the security relevant rules.

We will be using the following `.rubocop.yml` configuration to start out.

``` yaml
AllCops:
  DisabledByDefault: true

Security/Eval:
  Enabled: true
Security/JSONLoad:
  Enabled: true
Security/MarshalLoad:
  Enabled: true
Security/Open:
  Enabled: true
Security/YAMLLoad:
  Enabled: true
Bundler/InsecureProtocolSource:
  Enabled: true
Rails/OutputSafety:
  Enabled: true
```

We are disabling all the style and linting rules, and enabling only security-relevant ones. This is only done for simplicity in this blog post.

Running the `rubocop` command now should be way less noisy.

This is how it looks like on the RailsGoat repository:

``` shell
 $ bundlex exec rubocop
Inspecting 121 files
............C....................
Offenses:

app/controllers/password_resets_controller.rb:6:20: C: Security/MarshalLoad: Avoid using Marshal.load.
    user = Marshal.load(Base64.decode64(params[:user])) unless params[:user].nil?
                   ^^^^

121 files inspected, 1 offense detected
```

Not too impressive yet, but we are getting some relevant security info already.

Now we will add some more security rules.

Add the following to your Gemfile: `gem 'rubocop-gitlab-security'` and run `bundle install again`.

Now add the following to the configuration file `rubycop.yml`:

``` yaml
GitlabSecurity/DeepMunge:
  Enabled: true
GitlabSecurity/JsonSerialization:
  Enabled: true
GitlabSecurity/RedirectToParamsUpdate:
  Enabled: true
GitlabSecurity/SendFileParams:
  Enabled: true
GitlabSecurity/SqlInjection:
  Enabled: true
GitlabSecurity/SystemCommandInjection:
  Enabled: true
```

Those curated rules by the [GitLab team](https://gitlab.com/gitlab-org/rubocop-gitlab-security) add tremendous value to our security setup.

Now we need to require the new modules when running RuboCop:

Either by running:

``` shell
 bundle exec rubocop --require rubocop-gitlab-security
```

or add this to the `rubocop.yml`:

``` yaml
require: rubocop-gitlab-security
```

We can now find more security problems in the RailsGoat repository. Here is a gist with a sample report:https://gist.github.com/pxlpnk/958c500aab22f90b54918d6d9573251d


To configure the RakeTasks add:

``` ruby
require 'rubocop/rake_task'
RuboCop::RakeTask.new do |task|
  task.requires << 'rubocop-gitlab-security'
end
```

to your RakeFile and run it: `rake rubocop`

## Fixing Findings

To not drown in findings I recommend you configure and enable one scanner at a time.

**Start with high severity findings and filter out the rest.**

Some of the results will be false positives or are no danger at all for various reasons. They can usually be ignored and added to a list to not be noisy.

Once you have fixed or muted the findings and it behaves as you would like, move on to the next one.

When you have reached the point that you feel happy and comfortable with your setup, enable these tools to fail your CI builds and run them on every code change you commit.

Now you will always know when something is not up to your security standards.

## Hosted Services and Other Alternatives

In addition to the open source tools that are available, there are also a set of commercially available tools.

[GuardRails](https://www.guardrails.io) runs all the tools from this article. The service will post a comment on your GitHub pull request when they detect something. It is a zero-configuration security tool that does a bunch of heavy lifting for you and filters out all the false positives.

You also have companies like [Snyk](https://snyk.io/) that focus only on your dependencies, and will alert you when they detect new vulnerabilities. [GitHub](https://github.com) and [GitLab](https://gitlab.com/) also provide this as part of their offerings.

## Open Source Security Tools are Great

The ruby community has put massive effort into creating those tools. They are free for everyone to use and should be supported!

If you can afford it, send them some money or other support so they can continue and improve the tools in the future.

How do you secure your codebase? Let me know at [andy@occamslabs.com](mailto:andy@occamslabs.com).