Should I implement incorrect password delay in a website or a webservice?

I assume that your intention with the failure delay is to prevent brute force attacks: if an attacker is trying to guess a user's password, she will first fail many times; if we can make those failures take a substantial amount of time longer, then it will make the attack an order of magnitude harder, and thus unlikely to succeed (in a reasonable time frame).

However.

This assumes that the attacker waits patiently between login attempts. And, as we all know, cyberhackers are a very polite and patient folk.
That said, some attackers may choose NOT to wait, and simply send many requests in parallel. If a login attempt doesn't receive a response immediately, the attacker can interpret that as a failed attempt, kill that request, and move on the next one.

An extra benefit of this scheme is that it would be that much easier for an attacker to create unreasonable load on the server (just send a lot of failing login requests, each one will occupy a thread for several seconds...), and possibly even succeed in DoSing the server.

In fact, the main problem with this solution is that it precisely does NOT prevent many parallel requests. If an attacker is attempting an online brute force attack, she is not going to sit in front of the keyboard typing in many passwords, one after the other, as fast as Hugh Jackman possibly can - if that was the case, you would only be at risk if the user has a dead simple password.
In reality, she will have a script or automated tool send (almost) as many requests as the server can handle, and then keep going. The risk is not that someone will try 30 different passwords a minute, it's 1000 passwords a minute, or 10,000.

The only way to prevent that is user throttling / account lockout / incremental suspension - call it what you will, this is all basically the same idea of allowing X number of login attempts per account within a given timeframe.
So even though this doesn't cut down to "a single login attempt at a time", it does get close enough.


Part of the problem is that keeping the connection open while you wait for the delay to expire uses precious resources, particularly under certain popular configurations where the number of simultaneous connections allowed is pretty minimal.

An ideal solution is to architect your system as follows:

  • Design the logic first into the UI. A failed login returns the failure status immediately, but there's a delay before the UI resets to allow an additional login attempt. This isn't to enforce the rule, but rather to ensure that the a well-behaved user never sees an error message.

  • Enforce the logic on the backend by immediately returning an error status for any login attempts during the "cool-down" period. Don't even check to see if the password was correct, just fail immediately while consuming as few resources as possible.

  • To test to see whether a login attempt is allowed yet, the best solution is to use something lightweight, like memcached. For example, after a failed attempt with a given username, store in memcached the time that the cool-down expires. Then, when fielding new password attempts, check the entry in memcached to see if the cool-down period is up yet.

  • Enforce the same logic on a per-IP basis, not just per username basis. I shouldn't be able to guess thousands of passwords a second just by rotating through usernames.

  • Implement an exponential backoff. This is a bit of extra credit, but 2 attempts in 1 second isn't a big deal, but 50 attempts in 5 minutes is a big problem. This may be a bit harder to design, but repeated failures should trigger longer reset times. This could be as simple as keeping a failure counter (again, in memcached) and calculating the next cool-off as a function of that counter. The per-IP logic would have to be a bit different, though, since you don't want the attacker to be able to reset his counter just by sending a known user's credentials.


You want your server to do as little work as possible, to avoid DoSing yourself. Account lockout is great for DoSing your users.

if count(unsuccessful authentications for username U) > threshold then demand solved CAPTCHA

if count(unsuccessful authentications for password P) > threshold then demand solved CAPTCHA

if dislike CAPTCHA then demand Proof of Work

(make the client calculate the prime factors of a real big number)