The Rails Security Toolkit
Dive into Web Security to understand how Rails handles common attacks
In Ruby on Rails, building web applications is straightforward, but securing them is crucial. Just as you wouldn’t leave your front door open, you shouldn’t leave your app vulnerable to attacks. In this blog, we’ll explore common security issues and how to address them, keeping your Rails app safe and sound.
SQL Injection
SQL injection is a vulnerability that allows an attacker to insert or manipulate SQL queries by exploiting user input fields. This can lead to unauthorized access, data leaks, or even data deletion.
Suppose you want to find a user by their name.
# This code is like leaving your windows wide open.
User.where("name = '#{params[:name]}'")
If a malicious user inputs something like '; DROP TABLE users; --
in the name attribute, they could potentially delete your entire user table.
To prevent these attacks, we can take precautions by utilizing Rails’ built-in protections. Specifically, we can safeguard against SQL injection by using parameterized queries.
# Securely handling user input to prevent SQL injection.
User.where(name: params[:name])
Rails’ ActiveRecord automatically handles this for you, ensuring that user input is safely escaped and inserted into your queries.
CSRF (Cross-Site Request Forgery)
CSRF is an attack where users are tricked into performing actions on a web application without their consent, exploiting their authenticated session. For example, if a user is logged into their bank account on examplebank.com
, an attacker can create a malicious site, malicioussite.com
, with a hidden code that submits a request to transfer money from the user’s account.
Rails protects against CSRF attacks by default by using a security token in forms to verify the legitimacy of the requests.
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
end
In your forms, Rails automatically adds the CSRF token:
<!-- Rails forms include CSRF protection automatically. -->
<%= form_with url: some_path do |form| %>
<!-- form fields -->
<% end %>
XSS (Cross-Site Scripting)
XSS attacks happen when an attacker inserts harmful scripts into web pages, which run in other users’ browsers. This can steal data or make unwanted changes on their behalf. Clickjacking is related: it uses iframes to hide elements or trick users into clicking on something they didn’t intend (clicking over a button from an iframe), leading to unwanted actions or data exposure. Both types of attacks trick users and exploit security flaws.
<!-- Directly rendering user input without any sanitization. -->
<p><%= params[:message] %></p>
If a user inputs a script tag like <script>alert('Hacked!');</script>
, it will execute when other users view the page.
<!-- Use Rails' sanitization methods to safely display user input. -->
<p><%= sanitize(params[:message]) %></p>
Rails includes several built-in protections against XSS attacks. One key method is sanitize
, which removes potentially harmful code from user input before it is displayed. Additionally, Rails automatically escapes HTML in views by default, converting user-generated content into plain text and preventing scripts from executing. These mechanisms work together to help ensure the security of your application.
<!-- This code automatically escapes HTML. -->
<p><%= @user_message %></p>
In this example, if @user_message
contains HTML tags, Rails will escape them, so they are displayed as plain text rather than being interpreted as HTML or JavaScript. Additionally, Rails provides html_safe
and related methods to control when content should be treated as HTML.
Note: Using
html_safe
on untrusted input can expose your application to XSS attacks.
Mass Assignment Vulnerability
Mass assignment occurs when an attacker can modify attributes that should not be accessible, often due to improper handling of user input.
When creating or updating a user within an action can be given as below,
# This is like saying, “Go ahead, do whatever you want with my data.”
User.create(params[:user])
Allowing all data in params[:user]
can be risky, as it may include unwanted or malicious data. By using strong parameters, you ensure that only specified attributes are permitted for mass assignment, enhancing security by restricting which attributes can be accessed.
class UsersController < ApplicationController
def create
User.create(user_params)
end
private
def user_params
params.require(:user).permit(:name, :email)
end
end
Rate Limiting: Stopping Brute Force and Denial of Service (DoS) Attacks
Rate limiting is a technique used to prevent abuse of your application by restricting the number of requests a user or IP address can make in a given time period. This is especially useful for stopping brute force attacks (where attackers try many passwords to gain access) and denial of service (DoS) attacks (where attackers flood your server with requests to overwhelm it).
One popular way to implement rate limiting in Rails is by using the rack-attack
gem. This gem provides a simple way to throttle and block requests based on various criteria.
# config/initializers/rack_attack.rb
class Rack::Attack
# Throttle requests by IP address
throttle('requests by ip', limit: 100, period: 1.hour) do |request|
request.ip
end
# Throttle login attempts by IP address
throttle('logins by ip', limit: 5, period: 20.seconds) do |request|
if request.path == '/login' && request.post?
request.ip
end
end
# Blocklist IP addresses (e.g., known bad IPs)
blocklist('block bad IPs') do |request|
# Replace with actual IPs to block
['192.168.1.1'].include?(request.ip)https://tadhao.medium.com/constraints-in-rails-router-58f389031463
end
# Custom response for throttled requests
self.throttled_response = lambda do |env|
[ 429, { 'Content-Type' => 'text/plain' }, ["Throttle limit exceeded. Try again later."]]
end
end
In Rails, you can use gems like rack-attack
or rack-throttle
to easily implement rate limiting, or create custom middleware for more control.
Additionally, constraints in web applications can also be used to manage and restrict various aspects of requests and resources.
Conclusion
Understanding and addressing these common security threats is crucial for maintaining the safety and integrity of your Rails application. By using Rails’ built-in protections and following best practices, you can safeguard your application from these vulnerabilities.