Rack::Attack was written for the following problems:
- Is there a general high volume of requests from an IP?
- If so, I want to temporarily blacklist certain IPs
- How to throttle login attempts from an IP?
- But also throttle login attempts to a certain account because many IPs may be involved in the attack.
- I want to see what’s happening in the app
This is where it all started at Kickstarter.
Unless you know what your users are doing in the application, it’s better to start with the track feature of Rack:Attack. Once you know how many requests are normal you can enforce throttles.
Is it the solution to all my problems?
Rack::Attack is one piece in the puzzle, it will help to see how the application is used and to block some percentage of malicious or annoying requests. However, DoS or DDoS attacks will be very hard (if not impossible) to fend off completely.
The response of Rack::Attack should be a Rack application, by default it just returns a 429 HTTP status code (as a Rack application). If you rather want to render a static HTML page, use ActionDispatch::PublicExceptions to return a Rack app and render a page in the /public directory.
Search engine spiders
You’ll probably want to whitelist the IPs of search engine spiders. However, they have a huge range of IPs, so it would be a full-time job to keep up. So you can check the user agent of the request to be one of the known and then whitelist that IP. A user agent is just a string that can be faked. However, you can do a reverse DNS lookup of the accessing IP address and then do a forward DNS lookup on that domain and compare the two IPs. That way you make sure it’s really coming from GoogleBot, Bingbot or Yahoo.
How to whitelist known IPs and its subnets?
What’s a subnet? For example, you might want to whitelist all CloudFlare IPs in one go.
You can subscribe to the rack.attack notification to monitor the limits and to (asynchronously) send a custom message to a sysadmin.
ActiveSupport::Notifications.subscribe("rack.attack") do |name, start, finish, request_id, req| # req.env["rack.attack.match_type"] will be e.g. :track, :throttle end
See http://librelist.com/browser/rack.attack.announce/ and send an e-mail to email@example.com to subscribe