rack-attack doesn't blacklists any ip

1.9k Views Asked by At

Its my first interaction with rack-attack so please feel free to point out any mistakes I might have in the code. what I am trying is to blacklist those ip which are trying to access routes like "/azenv.php", "/setup.php" etc.. As these people are constantly hitting with some random .php url and probably trying to take down the server, I thought it might be a good idea to start blocking them but apparently rack-attack isn't blocking any ip which tries to access url mentioned above.

block of code which I am trying to run is:

class Rack::Attack

  Rack::Attack.whitelist('allow from localhost') do |req|
  # Requests are allowed if the return value is truthy
  '127.0.0.1' == req.ip || '::1' == req.ip || '122.166.130.230' == req.ip
  end

  Rack::Attack.blacklist("Block Referrer Analytics Spam") do |request|
    spammerList = ENV.has_key?("spammerList") ? ENV["spammerList"].split(',') : []
    spammerList.find { |spammer| request.referer =~ %r{#{spammer}} }
  end

  Rack::Attack.blacklist('bad_login_ip') do |req|
   (req.post? && req.path == "/users/sign_in" && IPCat.datacenter?(req.ip))
  end

  Rack::Attack.blacklist('Stupid IP for PHP') do |req|
    if req.path == "/azenv.php" || req.path == "/testproxy.php" || req.path == "//web/scripts/setup.php"
      req.ip
    end
    # req.path.include?(".php")
  end

  Rack::Attack.throttle('req/ip', limit: 300, period: 5.minutes) do |req|
    req.remote_ip if ['/assets', '/check'].any? {|path| req.path.starts_with? path }
  end

  Rack::Attack.throttle('req/ip', :limit => 5, :period => 20.seconds) do |req|
    if req.path == '/users/sign_in' && req.post?
      req.ip
    end
  end

  Rack::Attack.throttle("logins/email", :limit => 5, :period => 20.seconds) do |req|
    if req.path == '/users/sign_in' && req.post?
      # return the email if present, nil otherwise
      req.params['email'].presence
    end
  end
end

few of the blocks are from their wiki itself. please make a correction if anything is wrong here.

UPDATE

this is the piece of code I am trying from the given example:

Rack::Attack.blacklist('fail2ban pentesters') do |req|
  # `filter` returns truthy value if request fails, or if it's from a previously banned IP
  # so the request is blocked
    Rack::Attack::Fail2Ban.filter("pentesters-#{req.ip}", :maxretry => 1, :findtime => 10.minutes, :bantime => 5.minutes) do
      # The count for the IP is incremented if the return value is truthy
      req.path.include?('/testproxy.php') ||
      req.path.include?('azenv.php') 

    end
  end
2

There are 2 best solutions below

0
On

Did you try to move the environment variables out of the block,

For example:

  spammerList = ENV.has_key?("spammerList") ? ENV["spammerList"].split(',') : []

  Rack::Attack.blacklist("Block Referrer Analytics Spam") do |request|
    spammerList.find { |spammer| request.referer =~ %r{#{spammer}} }
  end
2
On

@abhinay can you please clarify which requests are successful that you'd expect to be blocked?

If you want to block all request from an IP address that has made a few PHP reqs, you want a Fail2Ban, like @frederickcheung suggested.

The readme and wiki have examples.