Ruby on Rails Developer Series: Ensuring Security is Covered in Your Application

Written by: Evan Glazer

4 min read

Stay connected

Welcome to the last and fourth blog post in my Ruby on Rails Developer Series. In this part, our goal is to go over some major security themes to ensure best practices. We will piggyback from the project you have been building in the other parts and use project-specific scenarios that will help secure the application. The series theme is to make you feel confident as an engineer in building a structured project with Ruby on Rails.

1. Authentication

Having authentication set up helps verify that the user is sanctioned to have access. Say you wanted to access a specific item in our Todo list todos/{:todo_id}/item/{:item_id}, however, if we don't validate, the user has access to view records. They can easily change the numbers of the todo_id and item_id and view those. I recommended you use an existing gem-like devise for authentication. Devise uses Bcrypt which makes it extremely difficult to for hackers to compute a password as it's computationally expensive with time. Devise has modules to also help with recovering passwords, registering, tracking user sign-ins, locking records, etc.

2. Strong Parameters

Having strong parameters is when you securely permit the data being sent to you from a request. Let us say we created a form that creates a Todo record: If we followed this common pattern Todo.create(params[:todo]. And say the form was altered with fields that don't exist in the model then rails will raise an exception. The same scenario works for updating values in a form if there is something we didn't want to be updated. What do I do? By using strong parameters, you whitelist the values that can be used.

params.require(:todo).permit(:name, :priority)

Now if the user submits the form with incorrect data to the parameterized fields the form will throw an error. How do I use it?

def create
def todo_params
    params.require(:todo).permit(:name, :priority)

3. Slug it!

A slug is part of a URL that identifies a particular record in an easy-to-read form. Slugs are good because we don't have to reveal the id of the record. I recommend using FriendlyId as it's the “Swiss Army bulldozer” of slugging and permalink plugins for ActiveRecord. After implementing, we can change our show methods to look like this: Todo.friendly.find(params[:id]) params[:id] - will contain the slug as we now use it as the id of the record.

4. Use HTTPS

Protect sensitive data, especially logins or payment pages. These are easily sniffed when traffic is unencrypted since cookies are easily obtainable through cross-site scripting (XSS). In the application config file you will need to specify config.force_ssl = true. Learn how to create an SSL certificate here.

5. Cross-Site Request Forgery (CSRF)

What is this? The attack method of cross-site request forgery is the idea that someone can insert malicious code into the application and trick the server to think the user is authenticated. This could allow the attacker to execute unauthorized commands. How do I enable this? Add protect_from_forgery with: :exception in the application controller. You can rescue forgery if the request is invalid as follows:

rescue_from ActionController::InvalidAuthenticityToken do |exception|
  sign_out_user # Example method that will destroy the user cookies

6. Check for Active Record Exceptions

One good thing we did in the previous part of the series was create an Exception Concern that sat on the top layer of the Application Controller to guard for specific application Active Record exceptions. The module below rescues these specific Active Record Exceptions:

module ExceptionHandler
  extend ActiveSupport::Concern
  included do
    rescue_from ActiveRecord::RecordNotFound do |e|
      render json: { message: e.message }, status: 404
    rescue_from ActiveRecord::RecordInvalid do |e|
      render json: { message: e.message }, status: 422

You can find more exceptions to guard for here.

Wrapping up the series

You have done it! Time to pat yourself on the back as we have planned to build our application and have built a structured project using Ruby on Rails. In this series, the goal was to outline how to bolster your API with strong top layers of infrastructure and Postgres, dockerize your project and add security layers to mitigate attacks to your application. I wanted to thank everyone for reading this series and I hope you feel more confident as an engineer building a rails application! I hope outlined the other parts for you to (re)visit. Part One Part Two Part Three

Additional resources

Stay up to date

We'll never share your email address and you can opt out at any time, we promise.

Loading form...
Your ad blocker may be blocking functionality on this page. Please disable for an improved experience.