I am trying to write a script to prevent brute-force login attempts in a website I'm building. The logic goes something like this:
sleep(10)
, then report a login failure to the user.Explaining this to a co-worker, I was asked how this would help if a hacker sent, say, 1000 requests in one second. Would the first 5 would return immediately, and then the remaining 995 all take only 10 seconds?
I have a sneaking suspicion that I don't fully understand how HTTP works - is that situation above even possible, or is there a limit to the number of concurrent requests that a server will handle from one client?
Would a better solution be to have an increasing sleep time?
sleep($numRequestsInLast5Minutes - 5)
So the first 5 would be fast, and then every subsequent one would increase the sleep.
The problem is the balance between user accessibility and attacker model.
If not password correct for a certain number of time:
block the user
send a reset link to the user
User: could be blocked, and they don't like to reset
Attacker: blocked all users by trying to authenticate to all users (especially if all logins are publicly available)
If not password correct:
sleep(amount_of_time)
The question is: what is the value of 'amount_of_time' ?
User: can be annoying to wait 'amount_of_time' for each error
Attacker: keep trying, with lower test / seconds
If not password correct:
sleep(amount_of_time)
amount_of_time = amount_of_time * 2
User: less annoying for few password mistakes
Attacker: block the user to connect by sending lot of incorrect password
If not password correct for a certain number of time:
submit a CAPTCHA
User: need to resolve the CAPTCHA (not too complex)
Attacker: need to resolve the CAPTCHA (must be complex)
Good solution (and used by a lot of sites) but be careful to our CAPTCHA. implementation. Anyway there is a trick (see next solution).
If not password correct for a certain number of time:
block the IP
(eventually) send a reset link
User: User may be blocked because he cannot correctly remember his password.
Attacker: trying the same password with different user, because blocking is based on number of login by user.
If several login attempts failed whatever is the user by an IP :
print a CAPTCHA for this IP
User: User cannot be IP blocked but must remember its password.
Attacker: difficult to have an efficient brute-force attack.
Is the login form or the login submit link which is blocked ? Blocking the login form is useless.
Resistance to brute-force is FIRST a problem of password complexity, so you need a strict password policy (especially in the case of distributed brute force).
I don't mention the fact to hash your passwords with salt, you're already doing this right ? Because if it is easier to access to the password database than brute-forcing, the attacker will choose this solution ("A chain is only as strong as its weakest link").