| examples | ||
| lib/rack | ||
| spec | ||
| .gitignore | ||
| .travis.yml | ||
| Gemfile | ||
| rack-attack.gemspec | ||
| Rakefile | ||
| README.md | ||
Rack::Attack!!!
A DSL for blocking & thottling abusive clients
Rack::Attack is a rack middleware to protect your web app from bad clients. It allows whitelisting, blacklisting, and thottling based on arbitrary properties of the request.
Thottle state is stored in a configurable cache (e.g. Rails.cache), presumably backed by memcached.
Installation
Install the rack-attack gem; or add it to you Gemfile with bundler:
# In your Gemfile
gem 'rack-attack'
Tell your app to use the Rack::Attack middleware. For Rails 3 apps:
# In config/application.rb
config.middleware.use Rack::Attack
Or for Rackup files:
# In config.ru
use Rack::Attack
Optionally configure the cache store for throttling:
Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new # defaults to Rails.cache
Note that Rack::Attack.cache is only used for throttling, not blacklisting & whitelisting. Your cache store must implement increment and write like ActiveSupport::Cache::Store.
How it works
The Rack::Attack middleware compares each request against whitelists, blacklists, and throttles that you define. There are none by default.
- If the request matches any whitelist, it is allowed. Blacklists and throttles are not checked.
- If the request matches any blacklist, it is blocked. Throttles are not checked.
- If the request matches any throttle, a counter is incremented in the Rack::Attack.cache. If the throttle limit is exceeded, the request is blocked and further throttles are not checked.
Usage
Define blacklists, throttles, and whitelists.
Note that req is a Rack::Request object.
Blacklists
# Block requests from 1.2.3.4
Rack::Attack.blacklist('block 1.2.3.4') do |req|
# Request are blocked if the return value is truthy
'1.2.3.4' == req.ip
end
# Block logins from a bad user agent
Rack::Attack.blacklist('block bad UA logins') do |req|
req.post? && request.path == '/login' && req.user_agent == 'BadUA'
end
Throttles
# Throttle requests to 5 requests per second per ip
Rack::Attack.throttle('req/ip', :limit => 5, :period => 1.second) do |req|
# If the return value is truthy, the cache key for
# "rack::attack:#{Time.now.to_i/1.second}:req/ip:#{req.ip}"
# is incremented and compared with the limit.
# If falsy, the cache key is neither incremented or checked.
req.ip
end
# Throttle login attempts for a given email parameter to 6 reqs/minute
Rack::Attack.throttle('logins/email', :limit => 6, :period => 60.seconds) do |req|
req.post? && request.path == '/login' && req.params['email']
end
Whitelists
# Always allow requests from localhost
# (blacklist & throttles are skipped)
Rack::Attack.whitelist('allow from localhost') do |req|
# Requests are allowed if the return value is truthy
'127.0.0.1' == req.ip
end
Responses
Customize the response of blacklisted and throttled requests using an object that adheres to the Rack app interface.
Rack:Attack.blacklisted_response = lambda do |env|
[ 503, {}, ['Blocked']]
end
Rack:Attack.throttled_response = lambda do |env|
# name and other data about the matched throttle
body = [
env['rack.attack.matched'],
env['rack.attack.match_type'],
env['rack.attack.match_data']
].inspect
[ 503, {}, [body]]
end
For responses that did not exceed a throttle limit, Rack::Attack annotates the env with match data:
request.env['rack.attack.throttle_data'][name] # => { :count => n, :period => p, :limit => l }
Logging & Instrumentation
Rack::Attack uses the ActiveSupport::Notifications API if available.
You can subscribe to 'rack.attack' events and log it, graph it, etc:
ActiveSupport::Notifications.subscribe('rack.attack') do |name, start, finish, request_id, req|
puts req.inspect
end
Motivation
Abusive clients range from malicious login crackers to naively-written scrapers. They hinder the security, performance, & availability of web applications.
It is impractical if not impossible to block abusive clients completely.
Rack::Attack aims to let developers quickly mitigate abusive requests and rely less on short-term, one-off hacks to block a particular attack.
Rack::Attack complements iptables and nginx's limit_zone module.
License
Copyright (c) 2012 Kickstarter, Inc
Released under an MIT License
