Rack Attack 404 errors and custom response message

09 Oct 2023

This week I will show you another Rack Attack trick.

Now let’s get to todays trick. If you don’t want to play whack a mole with bots, but and you don’t have a WAF like Wafris set up, you can block hosts if they make too many requests to the 404 page of your site with rack attack. To make this work, you need to redirect all your 404 traffic to a single URL and make sure it goes through your middleware stack instead of hitting the static 404.html file in the public filter. To achieve this, you can setup a custom exception app in config/application.rb

config.exceptions_app = self.routes

Then you create a controller and a view, and route 404 errors to that page:

# config/routes.rb
...
get "404", to: "welcome#notfound", code: 404
...

And in your application controller, you can rescue from ActiveRecord::Notfound and redirect to the error page:


  rescue_from ActiveRecord::RecordNotFound, with: :record_not_found

  def record_not_found
    redirect_to "/notfound"
  end

And the final step is to delete public/404.html.

Now that we have all 404 error pages ending up on /404, let’s add a rule to Rack Attack to block a client if hits more than 5 times the 404 page withing a 3 minutes interval:

# config/initializers/rack-attack.rb

class Rack::Attack
...
  blocklist("block 404") do |request|
    Allow2Ban.filter("notfound-#{request.ip}", maxretry: 5, findtime: 3.minutes, bantime: 1.day) do
    request.path == '/404'
  end
...
end

This blocking might be triggered by legitimate users too, so I recommend to create a custom response to tell them to contact support in case they got blocked:

# config/initializers/rack-attack.rb
Rack::Attack.blocklisted_responder = lambda do |request|
  [ 503, {}, ["You are blocked. If you think are not a bot and you think it was due to a mistake, reach out to us at support@yourdomain.com"]]
end

That’s it for this week, until next time!

Hire me for a penetration test

Let's find the security holes before the bad guys do.

Did you enjoy reading this? Sign up to the Rails Tricks newsletter for more content like this!

Or follow me on Twitter

Related posts