In a web application, one way to protect against password guessing attacks is to lock out accounts after a set number of failed logins. This could be done on both source IP address and username.
For example, the following table shows what happens when repeated attempts are detected. The system is set to lock accounts after 3 failed logins within a 5 minute window, for 5 minutes.
IP Time Username Creds Correct? Message Given
203.0.113.1 10:00:00 [email protected] N Bad username or password
203.0.113.1 10:00:01 [email protected] N Bad username or password
203.0.113.1 10:00:02 [email protected] N Bad username or password
203.0.113.2 10:00:03 [email protected] N Bad username or password
203.0.113.1 10:00:04 [email protected] N Login locked from your location
203.0.113.2 10:00:05 [email protected] Y Welcome!
203.0.113.2 10:00:06 [email protected] N Account locked
203.0.113.2 10:00:07 [email protected] Y Welcome!
203.0.113.1 10:01:00 [email protected] Y Login locked from your location
203.0.113.1 10:05:03 [email protected] Y Welcome!
Login attempts only count when credentials are validated (the process is to check for lockout first before validating credentials - if locked then credentials are not validated).
As you can see from the following, a malicious user (at IP 203.0.113.3
) can lock out an account causing a Denial of Service by repeatedly guessing the wrong password on purpose:
IP Time Username Creds Correct? Message Given
203.0.113.3 10:06:00 [email protected] N Bad username or password
203.0.113.3 10:06:01 [email protected] N Bad username or password
203.0.113.3 10:06:02 [email protected] N Bad username or password
203.0.113.3 10:06:03 [email protected] N Account locked
203.0.113.10 10:07:00 [email protected] Y Account locked
203.0.113.10 10:07:04 [email protected] Y Account locked
203.0.113.10 10:07:08 [email protected] Y Account locked
203.0.113.10 10:07:15 [email protected] Y Account locked
203.0.113.10 10:07:25 [email protected] Y Account locked
...preventing the real user at 203.0.113.10
from logging in.
An alternative to this is to artificially delay the HTTP response. Say first failed login delays by 1 second, the second by 2 seconds, the third by 4, and so on up to a total of 16 seconds. If their account is being attacked, the user will see a spinning circle in their browser while they wait for the HTTP response to their login request.
Are there any drawbacks to this? The above would now look like the following (say there is a 1 second delay as default, due to bcrypt iterations):
IP Req Time Resp Time Username Creds Correct? Message Given
203.0.113.3 10:06:00 10:06:01 [email protected] N Bad username or password
203.0.113.3 10:06:01 10:06:03 [email protected] N Bad username or password
203.0.113.3 10:06:03 10:06:08 [email protected] N Bad username or password
203.0.113.3 10:06:08 10:06:17 [email protected] N Bad username or password
203.0.113.10 10:06:18 10:06:35 [email protected] Y Welcome!
Note that the artificial delay (when active) is across threads, meaning the attacker cannot send requests from a single IP at any faster rate. A login from a different IP is not queued, although it will still experience any artificial delay built up via incorrect attempts on the username.
As you can see, the user at 203.0.113.10
is not denied access - they simply have to wait 17 seconds for their login to complete, while the attacker has to delay their attack. Therefore it is effective in preventing password guessing attacks.
My question is what are the negatives of this approach, and why don't you see this type of approach more often rather than the blanket lockout that can cause denial of service for users?