Rack::Attack Documentation
repository·main·Indexed 26 days ago
https://github.com/rack/rack-attackA Rack middleware for Ruby applications that protects Rails and Rack apps from abusive clients. It provides tools to safelist, block, and throttle requests based on request properties. Features include Fail2Ban and Allow2Ban filters, customizable blocklist and throttle responses, and integration with ActiveSupport::Notifications for monitoring and logging.
What's inside Rack::Attack
- Rack::Attack is a Rack middleware designed to protect Rails and Rack applications from abusive clients. It allows you to define rules to allow, block, or throttle requests based on various request properties.
Understand the Rack::Attack request processing logic
mainRack::Attack processes requests through a specific hierarchy. Once a request matches a rule, the subsequent rules are not evaluated:
- Safelists: If a request matches a safelist, it is allowed immediately.
- Blocklists: If not safelisted, but matches a blocklist, the request is blocked.
- Throttles: If not safelisted or blocklisted, but matches a throttle, a counter is incremented in
Rack::Attack.cache. If the limit is exceeded, the request is blocked. - Tracks: If none of the above match, all
tracksare checked (for logging/measuring purposes), and the request is allowed.
Set up the development environment for Rack::Attack
mainTo develop on Rack::Attack, you must have both Redis and Memcached running locally. They must be bound to
127.0.0.1on their default ports and accessible without authentication:- Redis: Port
6379 - Memcached: Port
11211
- Redis: Port
Blocklist Using Environment Variables
mainTo simplify maintenance, you can configure blocklists using values from environment variables. A common pattern is to split a comma-separated string from an ENV variable into an array and then convert that array into a
Regexpfor matching.class Rack::Attack # Split on a comma with 0 or more spaces after it. # E.g. ENV['HEROKU_VARIABLE'] = "foo.com, bar.com" # spammers = ["foo.com", "bar.com"] spammers = ENV['HEROKU_VARIABLE'].split(/,\s*/) # Turn spammers array into a regexp spammer_regexp = Regexp.union(spammers) # /foo\.com|bar\.com/ blocklist("block referer spam") do |request| request.referer =~ spammer_regexp end endImplement Exponential Backoff Throttling
mainYou can mimic exponential backoff by layering multiple
throttledefinitions with linearly increasing limits and exponentially increasing periods. This allows for progressively stricter limits as requests continue.# Allows 20 requests in 8 seconds # 40 requests in 64 seconds # ... # 100 requests in 0.38 days (~250 requests/day) (1..5).each do |level| throttle("logins/ip/#{level}", :limit => (20 * level), :period => (8 ** level).seconds) do |req| if req.path == '/login' && req.post? req.ip end end endInstall Rack::Attack
mainTo install Rack::Attack, add the gem to your
Gemfileand runbundle, or install it directly via the command line.Using Bundler: Add this to your
Gemfile:gem "rack-attack", "~> 6.8"Then run:
bundleDirect Installation:
gem install rack-attackBlocklist Using Rails.cache
mainYou can configure blocklists to check values stored in
Rails.cache. This allows your application logic to dynamically add or remove IPs from a blocklist by writing to or deleting from the cache.# Block attacks from IPs in cache # To add an IP: Rails.cache.write("block 1.2.3.4", true, expires_in: 2.days) # To remove an IP: Rails.cache.delete("block 1.2.3.4") Rack::Attack.blocklist("block IP") do |req| Rails.cache.read("block #{req.ip}") endDefine Custom Request Helpers
mainYou can extend
Rack::Attack::Request(which inherits fromRack::Request) to add custom helper methods. These helpers can then be used withinsafelist,blocklist, orthrottleblocks to simplify logic.class Rack::Attack::Request < ::Rack::Request def localhost? ip == "127.0.0.1" end end Rack::Attack.safelist("localhost") { |req| req.localhost? }Install dependencies and run tests
mainFollow these steps to install the necessary dependencies and execute the test suite using Appraisal:
- Install standard dependencies:
bundle install - Install test-specific dependencies:
bundle exec appraisal install - Run the test suite:
bundle exec appraisal rake test
$ bundle install $ bundle exec appraisal install $ bundle exec appraisal rake test- Install standard dependencies:
Plug Rack::Attack into your application
mainRack::Attack must be added as middleware to your application to function.
For Rails applications
Rack::Attack is used by default in Rails. You can enable or disable it using:
Rack::Attack.enabled = falseFor Rack applications
Add the following to your
config.rufile:require "rack/attack" use Rack::AttackNote: By default, Rack::Attack will not perform any blocking or throttling until you define specific rules in your configuration.
# In config.ru require "rack/attack" use Rack::AttackEnable Retry-After header for throttled clients
mainTo help well-behaved clients know when they can retry a request, you can enable the
Retry-Afterheader by settingthrottled_response_retry_after_headertotrue.Rack::Attack.throttled_response_retry_after_header = trueConfigure the Rack::Attack cache store
mainBy default,
Rack::AttackusesRails.cache. If you want to use a different store, you can configure it viaRack::Attack.cache.store.Note: The cache store is only used for throttling. It is not used for blocklisting or safelisting. The store must implement
.incrementand.writemethods, similar toActiveSupport::Cache::Store.