17

我正在尝试编写一个脚本来防止在我正在构建的网站中进行暴力登录尝试。逻辑是这样的:

  1. 用户发送登录信息。
  2. 检查用户名和密码是否正确
    • 如果是,让他们进来。
    • 如果否,则在数据库中记录一次失败的尝试。检查给定时间范围内是否有太多失败(例如:5 分钟内失败):
      • 如果是,则暂停执行 10 秒:sleep(10),然后向用户报告登录失败。
      • 立即向用户报告登录失败

在向同事解释这一点时,有人问我,如果黑客在一秒钟内发送 1000 个请求,这将有什么帮助。前 5 个会立即返回,然后剩下的 995 个都只需要 10 秒吗?

我有一个偷偷摸摸的怀疑,我不完全理解 HTTP 是如何工作的——这种情况是否可能发生,或者服务器将处理来自一个客户端的并发请求的数量是否有限制?

更好的解决方案是增加睡眠时间吗?

sleep($numRequestsInLast5Minutes - 5)

所以前5个会很快,然后每个后续都会增加睡眠。

4

5 回答 5

15

问题在于用户可访问性和攻击者模型之间的平衡。

第一个解决方案

If not password correct for a certain number of time:
    block the user
    send a reset link to the user

用户:可能被阻止,并且他们不喜欢重置
攻击者:通过尝试对所有用户进行身份验证来阻止所有用户(特别是如果所有登录名都是公开可用的)

第二种解决方案

If not password correct:
    sleep(amount_of_time)

问题是: 'amount_of_time' 的值是多少?

用户:等待每个错误的“amount_of_time”可能很烦人
攻击者:继续尝试,测试/秒数较低

第三个解决方案

If not password correct:
    sleep(amount_of_time)
    amount_of_time = amount_of_time * 2

用户:密码错误少,不那么烦人
攻击者:通过发送大量错误密码来阻止用户连接

第四种解决方案

If not password correct for a certain number of time:
    submit a CAPTCHA

用户:需要解析验证码(不太复杂)
攻击者:需要解析验证码(必须很复杂)

很好的解决方案(并且被很多网站使用)但要小心我们的验证码。实施。无论如何,有一个技巧(请参阅下一个解决方案)。

第五种解决方案

If not password correct for a certain number of time:
    block the IP
    (eventually) send a reset link

用户:用户可能因为无法正确记住密码而被阻止。
攻击者:用不同的用户尝试相同的密码,因为阻止是基于用户的登录次数。

最终解决方案?

If several login attempts failed whatever is the user by an IP :
    print a CAPTCHA for this IP

用户:用户不能被 IP 封锁,但必须记住其密码。
攻击者:难以进行有效的蛮力攻击。

重要说明

登录表单或登录提交链接是否被阻止?阻止登录表单是没有用的。

抵抗暴力破解首先是密码复杂性的问题,因此您需要严格的密码策略(尤其是在分布式暴力破解的情况下)。

我没有提到用盐对密码进行哈希处理的事实,你已经在这样做了吗?因为如果访问密码数据库比暴力破解更容易,攻击者会选择这种解决方案(“一条链的强度取决于它最薄弱的环节”)。

于 2013-04-04T11:52:18.307 回答
13

我建议如果用户尝试不成功,比如超过五次五分钟,您503 Service Unavailable立即开始为该 IP 地址返回一个。当登录失败时,您可以使用 memcache 获取当前对 IP 的错误尝试,然后增加数量,并将其保存回 memcache,有效期为 5 分钟。

您不想sleep在 PHP 代码中添加 a,因为这将允许单个用户创建大量与您的 Web 服务器的连接,并可能导致其他用户瘫痪。

由于用户尚未登录,因此您没有会话 cookie,如果用户试图强行进入帐户,他们可能根本不会提供 cookie。

于 2009-11-13T05:58:39.957 回答
4

我用过这样的东西......

  1. 检查用户名和密码

    1.1 如果不匹配,则记录该组合的上次失败登录时间和失败登录次数。

    1.2 每次失败都会在能够登录失败计数 * 30 秒之间等待,最长可达 10 分钟(例如 10 分钟)。

  • 这意味着蛮力攻击将成倍地花费越来越长的时间。
  • 它可以锁定用户 - 但在锁定期间尝试登录时不会计算失败的登录。这应该将其最小化。

我已经开发了这个,但还没有发布到野外,所以任何反馈都将不胜感激。

于 2009-11-17T04:36:09.413 回答
2

我不确定最佳实践是什么,但在处理 DoS 攻击时,更好的策略是实际将流量您的服务器转移。设置超时实际上并没有帮助,因为您仍在处理请求并运行 PHP。

您是否考虑过设置另一个 Web 服务器来运行您的登录页面的更简单的精简版本?当用户尝试太多次(例如,数千次)时,发送一条消息来配置您的路由器并将该用户重定向到第二个 Web 服务器。

这就像当网站受到斜线效应的影响时,他们中的许多人只是将流量重定向,直到流量减少。

于 2009-11-13T05:49:02.433 回答
2

我创建了一个类来处理 PHP 中的蛮力攻击保护。

https://github.com/ejfrancis/BruteForceBlocker

它将站点范围内的所有失败登录记录在数据库表中,如果过去 10 分钟(或您选择的任何时间范围)内的失败登录次数超过设定的限制,它会强制执行时间延迟和/或验证码要求在再次登录之前。

例子:

//建立油门设置数组。(# 最近失败的登录 => 响应)。

$throttle_settings = [

    50 => 2,            //delay in seconds
    150 => 4,           //delay in seconds
    300 => 'captcha'    //captcha 

];

$BFBresponse = BruteForceBlocker::getLoginStatus($throttle_settings);

//$throttle_settings 是一个可选参数。如果不包含,将使用 BruteForceBlocker.php 中的默认设置数组

开关($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;

}

于 2014-06-14T22:34:03.940 回答