Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Throlled/blocklist by response code #675

Open
KieranP opened this issue Dec 2, 2024 · 2 comments
Open

Throlled/blocklist by response code #675

KieranP opened this issue Dec 2, 2024 · 2 comments

Comments

@KieranP
Copy link

KieranP commented Dec 2, 2024

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?

@santib
Copy link
Collaborator

santib commented Dec 3, 2024

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

@KieranP
Copy link
Author

KieranP commented Dec 3, 2024

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants