Skip to content
This repository has been archived by the owner on Oct 6, 2021. It is now read-only.

Progressive Login Attempt Rate-Limiting #35

Closed
paragonie-scott opened this issue Jun 18, 2016 · 2 comments · Fixed by #36
Closed

Progressive Login Attempt Rate-Limiting #35

paragonie-scott opened this issue Jun 18, 2016 · 2 comments · Fixed by #36

Comments

@paragonie-scott
Copy link
Member

paragonie-scott commented Jun 18, 2016

When many failed login attempts come from the same IP or user account, we should pause for a progressively longer time before beginning the Argon2i verification, growing exponentially until the delay reaches a cap. For example:

  • 1 failed attempt -> 0.25s
  • 2 failed attempts -> 0.5s
  • 3 failed attempts -> 1.0s
  • 4 failed attempts -> 2.0s
  • 5 failed attempts -> 4.0s
  • 6 failed attempts -> 8.0s
  • 7 failed attempts -> 16.0s
  • 8+ failed attempts -> 30.0s (assuming a cap of 30 seconds)

Additionally, after N (default: 3) failed attempts, we could allow the admin to optionally seal-then-log the attempted usernames and passwords.

This will help against two possible attacks:

  1. Online password guessing (which should be futile with strong passwords).
  2. Attempting to DoS via CPU usage in the Argon2i calculation.

Thanks to @jedisct1 for reminding me of these attack vectors.

@paragonie-scott
Copy link
Member Author

From @joepie91 over IRC:

(3:30:46 PM) joepie91: CiPHPer: obligatory note, be mindful of PHP pool size
(3:30:55 PM) joepie91: this can be used as a DoS vector in PHP
(3:31:07 PM) joepie91: by intentionally keeping processes alive
(3:31:16 PM) joepie91: and either taking up pool slots or taking up RAM
(3:31:27 PM) joepie91: (why the CGI model is bad, chapter 42)
(3:31:30 PM) CiPHPer: great point :)
(3:32:41 PM) joepie91: yeah, I think this is an unsolvable problem in PHP without resorting to HTTPd-level addons
(3:32:44 PM) joepie91: unfortunately
(3:33:10 PM) CiPHPer: aye
(3:33:15 PM) joepie91: no matter what you do, there's no way to sleep() without either keeping a PHP process tied up, or implementing JS-requiring retry logic
(3:33:31 PM) joepie91: (on the client side)
(3:33:40 PM) CiPHPer: the alternative is to die with an error message saying "try back in 29 seconds"
(3:33:50 PM) joepie91: yeah, but that's a UX stink
(3:33:52 PM) joepie91: :P
(3:33:57 PM) CiPHPer: of course

Would it make sense to make this configurable?

  • fast-exit -> Die with an error message.
  • sleep -> sleep($time)

@paragonie-scott
Copy link
Member Author

Throttling will be based on Username || IP address.

  • We use a dummy Argon2 hash to mitigate (not prevent!) valid usernames from being inferred via timing information.
  • If we go per-account, we can't throttle bad username guesses (still a DoS vector)
  • If we go per-IP, attackers with an entire /64 of IPv6 space will never run out
  • If we select based on both factors, we can cover the entire login process and make it harder for attackers to play whack-a-mole.

paragonie-scott pushed a commit that referenced this issue Jun 18, 2016
paragonie-scott added a commit that referenced this issue Jun 19, 2016
Implement Progressive Rate-Limiting, closes #35
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.