A simple application level DOS (Denial-Of-Service) preventor for small Rails apps
Ruby
Pull request Compare This branch is 1 commit ahead of srejbi:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
app/views/wait_a_minute
lib
Gemfile
MIT-LICENSE
README
Rakefile
wait_a_minute.gemspec

README

== WaitAMinute

A simple, application level DOS (Denial-Of-Service) protection tool for 
small Rails applications.

== How does it work?

Once WaitAMinute gem is installed and configured in a Rails application, it 
will run a before_filter on *every* call to any subclasses of ActionController.

The before hook checks if the IP is a 'friendly' one (eg. NewRelic monitoring), 
meaning it is allowed no matter what. 
For 'non-friendly' IP addresses, the before filter checks if the IP is not already
banned within a minute (hence the name of the gem), if not, it checks the number 
of previous requests from the given address within a configurable floating timeframe
and allows the request to be served only if the address did not exceed the allowed
maximum requests within the timeframe. WaitAMinute then stores the request IP and 
the timestamp along with a bit indicating if the request was refused or not.

If the IP is banned, WaitAMinute renders a page with HTTP status 503 telling the 
server is too busy to handle the request and that the user should retry after a minute.

== Installation

add the gem to your Gemfile then
# bundle install

== Configuration

in your application's root directory, 

run 
# rails g wait_a_minute:install

then
# rake db:migrate

finally revise and tweak
config/initializers/wait_a_minute.rb

WaitAMinute.lookback_interval - the floating timeframe size, 
eg. 2.minutes

WaitAMinute.maximum_requests - the max number of requests from a single IP 
within the timeframe, eg. 24 - along with the above it allows a request 
every 5 seconds from a single IP address

WaitAMinute.debug - set to true for having IP filtering logged

WaitAMinute.layout - if some layout is needed around the error page, specify it 
here /for best performance it is not recommended, we want banned IP's to use 
the least resources/

WaitAMinute.allowed_ips - an array of strings with IP addresses that never should 
be banned, eg, ['127.0.0.1'] (once tried that it works ok on the development box, 
likely want the local developer to pass through always)

== Customization

create app/views/wait_a_minute/wait_a_minute.html.erb and customize to your 
liking to override the default error page for banned IP addresses.

== Maintenance

from time to time WaitAMinute.cleanup should be called from a scheduled
script to flush obsolete request logs in order to keep an optimal
ActiveRecord performance in its filtering operations.

== Further considerations

as the piece of software works with the REMOTE_ADDR of the request, it is only 
suitable in environments where it reflects the original request address.
(eg. it won't work in an environment where a load balancer replaces the
REMOTE_ADDR address in the request)