Aug 28, 2023 - Salvatore Ferrucci

Protect your rails application with Rack Attack

Rack Attack is a widely embraced gem within the Ruby community, primarily employed for the purpose of throttling and mitigating abusive requests within Rack applications, notably including Ruby on Rails.

When harnessed effectively, it can serve as an invaluable security safeguard for your website, offering the capability to shield your web application from various types of attacks. This includes features such as IP whitelisting, dynamic request blocking based on specific criteria, and much more.

In this article, we will provide step-by-step instructions on how to seamlessly integrate and configure Rack Attack to bolster the security of your Ruby on Rails application.

Integrating with the application

To kickstart your journey with RackAttack, you'll first need to add it into your Gemfile and execute the bundle install command.

RackAttack is renowned for its extensive configurability, affording you the flexibility to establish rules and rate limits tailored to safeguard your application. By default, RackAttack remains dormant, refraining from any blocking or throttling, until you explicitly instruct it on what threats to guard against, achieved through the configuration of specific rules. In the context of Rails applications, this entails the creation of a new initializer file where you can craft and define your custom rules.

Usage

Safelists have the most precedence, so any request matching a safelist would be allowed despite matching any number of blocklists or throttles.

Whitelisting IP Addresses

To whitelist specific IP addresses and exempt them from rate limiting or blocking, you can add a whitelist configuration:

# config/initializers/rack_attack.rb

Rack::Attack.safelist('allow from trusted IPs') do |req|
  # Add your trusted IP addresses here
  ['192.168.1.1', '10.0.0.1'].include?(req.ip)
end

Requests from IP addresses listed in the safelist will not be subject to rate limiting or blocking.

Rate Limiting by Endpoint

You can set rate limits for specific endpoints or routes in your application. For example, to limit the number of requests to a specific API endpoint:

# config/initializers/rack_attack.rb

Rack::Attack.throttle('api_requests', limit: 20, period: 1.minute) do |req|
  # This will limit requests to the '/api/endpoint' path
  if req.path == '/api/endpoint' && req.post?
    req.ip
  end
end

In this example, requests to the /api/endpoint path are limited to 20 requests per minute per IP address.

Custom Blocklist Logic

If you want to implement custom logic to block certain IP addresses, you can use the blocklist with a custom block:

# config/initializers/rack_attack.rb

Rack::Attack.blocklist('block malicious IPs') do |req|
  # Define custom logic to block malicious IPs
  # For example, block IPs with a certain pattern in the user agent
  req.user_agent =~ /malicious_pattern/i
end

In this example, requests with a user agent matching the malicious_pattern regular expression will be blocked.

Dynamic Rate Limiting

RackAttack also allows you to set dynamic rate limits based on request parameters. For instance, you might want to rate limit requests based on the user's role or API key. Here's an example of how you can achieve this:

# config/initializers/rack_attack.rb

# Dynamic rate limiting based on user role
Rack::Attack.throttle('role_requests', limit: 50, period: 1.hour) do |req|
  # Check if the request contains a 'role' parameter
  if req.params['role'].present?
    # Rate limit based on the user's role
    req.params['role']
  end
end

In this case, requests are rate-limited based on the role parameter in the request, allowing you to set different rate limits for different user roles.

Customizing responses

You can customize the response when a request is throttled or blocked. For example, to return a custom view with an error message:

Rack::Attack.blocklisted_responder = lambda do |request|
  [ 503, {}, ApplicationController.render(template: 'errors/503')]
end

Now, when a request exceeds the rate limit, it will receive an HTML page with the "Service Unavailable" error message.

Tips

In addition to its robust configuration capabilities and integration into routes, RackAttack offers the convenience of querying storage for checks and rules, further enhancing its adaptability and extensibility.

By leveraging storage querying, developers can dynamically adjust security measures in response to changing conditions, enabling real-time threat monitoring and response strategies.

This feature empowers applications to retrieve and evaluate predefined rules, such as rate limits and blocklists, from storage repositories, enabling runtime updates without the need for code changes. This dynamic approach is particularly valuable in scenarios where security policies must adapt rapidly to emerging threats or evolving user behavior.

Furthermore, querying storage for checks and rules aligns RackAttack with the principles of scalability and maintainability, ensuring that web applications can efficiently adapt to security challenges as they arise.

Conclusion

In conclusion, the RackAttack Ruby gem is a versatile and powerful tool for enhancing the security of your web applications. With its flexible configuration options, the ability to apply rules directly in routes, and the capability to query storage for checks and rules, RackAttack provides developers with a comprehensive suite of tools to defend against various forms of attacks and vulnerabilities.

Whether you need to implement rate limiting, block malicious IPs, or dynamically adjust security measures, RackAttack empowers you to tailor your application's security strategy to your specific needs.

By integrating this gem into your Ruby on Rails application, you not only fortify your defenses but also gain the agility to respond swiftly to emerging threats and changing conditions. As you harness the potential of RackAttack, your web application's security will stand stronger and more adaptable than ever before.

Protect your rails application with Rack Attack via @safeforge

Click to tweet