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 CAPTCHA
User: need to resolve the CAPTCHA (not too complex) Attacker: need to resolve the CAPTCHA (must be complex)
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").
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.
我不确定最佳实践是什么,但在处理 DoS 攻击时,更好的策略是将流量从您的服务器转移。设置超时实际上并没有帮助,因为您仍在处理请求并运行 PHP。
您是否考虑过设置另一个 Web 服务器来运行登录页面的更简单的精简版本?当用户尝试次数过多(例如数千次)时,请发送一条消息来配置您的路由器并将该用户重定向到第二个 Web 服务器。
就像当网站受到斜线效应的打击时,许多网站只是将流量重定向,直到流量减少。
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.
//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;
}
I made a class that takes care of brute force attack protection in PHP.
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)
问题在于用户可访问性和攻击者模型之间的平衡。
第一个解决方案
用户:可能被阻止,并且他们不喜欢重置
攻击者:通过尝试对所有用户进行身份验证来阻止所有用户(特别是在所有登录信息都是公开可用的情况下)
第二个解决方案
问题是: 'amount_of_time' 的值是多少?
用户:等待每个错误“amount_of_time”可能会很烦人
攻击者:继续尝试,测试/秒数较低
第三种解决方案
用户:少数密码错误不那么烦人
攻击者:通过发送大量错误密码来阻止用户连接
第四种解决方案
用户:需要解析验证码(不要太复杂)
攻击者:需要解析验证码(必须很复杂)
很好的解决方案(并且被很多网站使用),但是小心我们的验证码。实施。无论如何,有一个技巧(请参阅下一个解决方案)。
第五种解决方案
用户:用户可能因为无法正确记住密码而被阻止。
攻击者:对不同的用户尝试相同的密码,因为阻止是基于用户的登录次数。
最终解决方案?
用户:用户不能被IP封锁,但必须记住其密码。
攻击者:很难进行有效的暴力攻击。
重要提示
登录表单或登录提交链接是否被阻止?阻止登录表单是没有用的。
抵抗暴力破解首先是密码复杂性的问题,因此您需要严格的密码策略(特别是在分布式暴力破解的情况下)。
我没有提到用盐对密码进行哈希处理的事实,您已经这样做了,对吗?因为如果访问密码数据库比暴力破解更容易,攻击者就会选择这种解决方案(“一条链的强度取决于其最薄弱的一环”)。
The problem is the balance between user accessibility and attacker model.
First Solution
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
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
User: less annoying for few password mistakes
Attacker: block the user to connect by sending lot of incorrect password
Fourth Solution
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
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 ?
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").
我建议,如果用户尝试不成功,例如超过五次五分钟,则立即开始针对该 IP 地址返回
503 Service Unavailable
。当登录失败时,您可以使用 memcache 获取当前 IP 的错误尝试,然后增加该数量,并将其保存回 memcache,并在 5 分钟内过期。您不想在 PHP 代码中设置
sleep
,因为这将允许单个用户创建与您的 Web 服务器的大量连接,并可能导致其他用户瘫痪。由于用户尚未登录,因此您没有会话 cookie,并且如果用户尝试暴力进入帐户,他们可能根本不会提供 cookie。
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.
我已经使用过类似的东西...
检查用户名和密码
1.1 如果不匹配,则记录该组合上次登录失败的时间以及登录失败的次数。
1.2 每次失败都会导致能够登录之间的等待时间,例如failsCount * 30秒,最多可达最大值(例如10分钟)。
我已经开发了这个,但尚未将其发布到野外,因此任何反馈将不胜感激。
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).
I've developed this but not released it into the wild yet, so any feedback would be appreciated.
我不确定最佳实践是什么,但在处理 DoS 攻击时,更好的策略是将流量从您的服务器转移。设置超时实际上并没有帮助,因为您仍在处理请求并运行 PHP。
您是否考虑过设置另一个 Web 服务器来运行登录页面的更简单的精简版本?当用户尝试次数过多(例如数千次)时,请发送一条消息来配置您的路由器并将该用户重定向到第二个 Web 服务器。
就像当网站受到斜线效应的打击时,许多网站只是将流量重定向,直到流量减少。
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.
我在 PHP 中创建了一个负责暴力攻击防护的类。
https://github.com/ejfrancis/BruteForceBlocker
它将整个站点范围内的所有失败登录记录在数据库中表中,如果过去 10 分钟(或您选择的任何时间范围)内登录失败的次数超过设定限制,则在再次登录之前会强制执行时间延迟和/或验证码要求。
例子:
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: