rack-attack
rack-attack copied to clipboard
Throlled/blocklist by response code
All examples and usages show how we can use the request to determine whether to block/throttle. However, is there any way to do so using the response? Using the request IP would mean that if an entire office logged in all around the same time on the same IP, they would throttle themselves, even if all those login requests were successful. Instead, I I want to throttle login requests by IP but only when those requests fail (i.e. a code other than 2xx). That way, when there are 5 or more unsuccessful login attempts within 5 minutes, it'll throttle/block the IP that caused that failed response. Is this possible?
Hi @KieranP
Using the request IP would mean that if an entire office logged in all around the same time on the same IP, they would throttle themselves, even if all those login requests were successful
That's correct. Maybe another option would be using the email, so different users on the same IP won't block each other. Here is an example https://github.com/rack/rack-attack/blob/main/examples/rack_attack.rb#L15-L20
@santib The trouble though is that doesn't provide any mitigations against simple attackers from scraping credentials or trying to break into accounts. They'll be able to try 1000s of emails without being locked out.
After evaluating rack-attack and several other options, we decided we needed to roll out our own throttling system that could be based on the login response, not just the request. It works something like this:
around_action :throttle_failed_logins, only: :create
def create
...
end
private
def throttle_failed_logins
if throttle_attempts_exceeded?
head(429) && return
end
yield
if response.status.in?([400, 401, 403, 404])
increment_failed_attempts!
end
if throttle_attempts_exceeded?
head(429) && return
end
true
end
And this seems to be working well. It will only increment per IP when the request fails. That way, if everyone in an office login successfully, no issue. It only triggers when there are 5+ failed logins from the same IP.
Bit of a pain to roll our own code instead of using something like rack-attack, and if rack-attack were to support this use case in the future we'd likely switch over to it, but for now this will do for us.
Hi @KieranP, sorry for the delay. Seems like blocking based on the response has always worked despite not being documented.
Please refer to https://github.com/rack/rack-attack/pull/646#issuecomment-2861354852 to see how to get it working with rack-attack.
Thank you
@santib I would recommend documenting that, otherwise someone else will open a ticket in the future asking the same thing :-)