diff --git a/README.md b/README.md index 269a82c..dd5704c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,87 @@ -# Rack::Attack - middleware for throttling & blocking abusive clients +# 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 + +Add `rack-attack` to your Gemfile or run + gem install 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 in your `config.ru`: + use Rack::Attack + +Optionally configure the cache store for throttling: + + Rack::Attack.cache.store = my_cache_store # defaults to Rails.cache + +Note that `Rack::Attack.cache` is only used for throttling, not blacklisting & whitelisting. + +## How it works + +The Rack::Attack middleware examines each request against *whitelists*, *blacklists*, and *throttles* that you define. +By default, there are no whitelists, blacklists, or throttles. + + * If the request matches any whitelist, the request is allowed. Blacklists and throttles are not checked. + * If the request matches any blacklist, the request 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 + + # 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 + + # 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:req/ip:#{req.ip}" is incremented and checked. + # 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 + + # 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 + +Note that `req` is a [Rack::Request](http://rack.rubyforge.org/doc/classes/Rack/Request.html) object. + +## Logging & Instrumentation + +## 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](http://wiki.nginx.org/HttpLimitZoneModule). ## Processing order * If any whitelist matches, the request is allowed @@ -6,4 +89,3 @@ * If any throttle matches, the request is throttled (unless a whitelist or blacklist matched) [![Travis CI](https://secure.travis-ci.org/ktheory/rack-attack.png)](http://travis-ci.org/ktheory/rack-attack) -