问题
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:
- User sends login information.
- Check if username and password is correct
- If Yes, let them in.
- If No, record a failed attempt in the database. Check if there's too many fails within a given timeframe (eg: 5 in 5 minutes):
- If Yes, then pause execution for 10 seconds:
sleep(10)
, then report a login failure to the user. - Report a login failure to the user immediately
- If Yes, then pause execution for 10 seconds:
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.
回答1:
The problem is the balance between user accessibility and attacker model.
First Solution
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)
Second solution
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
Third Solution
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
Fourth Solution
If not password correct for a certain number of time:
submit a catchpa
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).
Fifth 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.
Final Solution ?
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.
The important notes
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").
回答2:
I would suggest if the user has tried unsuccessfully, say more than five times and five minutes, you start returning a 503 Service Unavailable
immediately, for that IP address. When a login fails, you could use memcache to get the current bad attempts for an IP, and then increment the amount, and save it back to memcache with a 5 minute expiry.
You don't want to put a sleep
in your PHP code, as that will allow a single user to create lots of connections to your web server, and potentially bring down other users.
Since the user hasn't logged in, you don't have a session cookie, and if the user is trying to brute force their way into an account, they may not present a cookie at all.
回答3:
I have used something like this...
Check username and password
1.1 If no match then, record last failed login time for that combo and number of failed logins.
1.2 Each fail makes the wait between being able to login something like failsCount * 30 seconds, up to a maximum (such as 10 minutes).
- This means a brute force attack will exponentially take longer and longer.
- It could lock a user out - but it will not count a failed login whilst trying to login during the lockout period. This should minimise it.
I've developed this but not released it into the wild yet, so any feedback would be appreciated.
回答4:
I made a class that takes care of brute force attack protection in PHP.
https://github.com/ejfrancis/BruteForceBlocker
it logs all failed logins site-wide in a db table, and if the number of failed logins in the last 10 minutes (or whatever time frame you choose) is over a set limit, it enforces a time delay and/or a captcha requirement before logging in again.
example:
//build throttle settings array. (# recent failed logins => response).
$throttle_settings = [
50 => 2, //delay in seconds 150 => 4, //delay in seconds 300 => 'captcha' //captcha
];
$BFBresponse = BruteForceBlocker::getLoginStatus($throttle_settings);
//$throttle_settings is an optional parameter. if it's not included,the default settings array in BruteForceBlocker.php will be used
switch ($BFBresponse['status']){
case 'safe': //safe to login break; case 'error': //error occured. get message $error_message = $BFBresponse['message']; break; case 'delay': //time delay required before next login $remaining_delay_in_seconds = $BFBresponse['message']; break; case 'captcha': //captcha required break;
}
回答5:
I am not sure what the best practice is, but when dealing with DoS attacks, a better strategy is to actually divert traffic away from your server. Setting timeouts won't actually help because you're still processing the request and running PHP.
Have you considered setting up another web server running a simpler stripped down version of your login page? When the user tries too many times (e.g., thousands of times), send a message to configure your router and redirect this user to the second web server.
It's like when websites get hit with the slashdot effect, many of them just redirect traffic away until traffic is reduced.
来源:https://stackoverflow.com/questions/1727329/brute-force-dos-prevention-in-php