PHP 中的暴力破解/DoS 防护 [已关闭]

2022-08-30 23:07:10

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

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

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

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

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

sleep($numRequestsInLast5Minutes - 5)

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


答案 1

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

第一个解决方案

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

用户:需要解决CAPTCHA(不太复杂)
攻击者:需要解决CAPTCHA(必须复杂)

很好的解决方案(并且被许多网站使用),但要小心我们的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 阻止,但必须记住其密码。
攻击者:很难进行有效的暴力攻击。

重要说明

是登录表单还是登录提交链接被阻止?阻止登录表单是无用的。

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

我没有提到用盐散列密码的事实,你已经这样做了吗?因为如果访问密码数据库比暴力破解更容易,攻击者将选择此解决方案(“链的强度取决于其最薄弱的环节”)。


答案 2

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

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

由于用户尚未登录,因此您没有会话cookie,并且如果用户试图暴力破解帐户,则他们可能根本不会提供cookie。


推荐