PHP中的暴力/ DoS预防

时间:2009-11-13 05:37:35

标签: php security brute-force ddos

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

  1. 用户发送登录信息。
  2. 检查用户名和密码是否正确
    • 如果是,请让他们进来。
    • 如果否,则记录数据库中的失败尝试。检查在给定时间范围内是否有太多失败(例如:5分钟内5次):
      • 如果是,则暂停执行10秒:sleep(10),然后向用户报告登录失败。
      • 立即向用户报告登录失败
  3. 向同事解释这个问题时,有人问我,如果黑客在一秒内发送了1000个请求,这会有什么帮助。前5个会立即返回,然后剩下的995只需要10秒吗?

    我有一种潜在的怀疑,即我不完全理解HTTP是如何工作的 - 甚至可能是上述情况,还是服务器将从一个客户端处理的并发请求数量有限制?

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

    sleep($numRequestsInLast5Minutes - 5)
    

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

5 个答案:

答案 0 :(得分: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 catchpa

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

良好的解决方案(并被许多网站使用)但be careful to our CAPTCHA. implementation。无论如何,有一个技巧(见下一个解决方案)。

第五种解决方案

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,但必须记住密码 攻击者:难以进行有效的暴力攻击。

重要说明

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

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

我没有提到用盐哈希你的密码的事实,你已经这样做了吗?因为如果访问密码数据库比强制攻击更容易,攻击者将选择此解决方案(“A链只有最薄弱的链接”)。

答案 1 :(得分:13)

我建议如果用户尝试失败,例如超过五次和五分钟,则立即开始为该IP地址返回503 Service Unavailable。当登录失败时,您可以使用memcache获取IP的当前错误尝试,然后增加金额,并将其保存到memcache,并在5分钟到期。

您不希望在PHP代码中放置sleep,因为这将允许单个用户创建大量与Web服务器的连接,并可能导致其他用户失望。

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

答案 2 :(得分:4)

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

  1. 检查用户名和密码

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

    1.2每次失败都会在能够登录failCount * 30秒之间等待,直到达到最大值(例如10分钟)。

    • 这意味着蛮力攻击会指数越来越长。
    • 它可能会锁定用户 - 但在锁定期间尝试登录时,它不会计入失败的登录信息。这应该最小化它。

    我已经开发了这个,但还没有将它发布到野外,所以任何反馈都会受到赞赏。

答案 3 :(得分:2)

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

https://github.com/ejfrancis/BruteForceBlocker

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

示例:

  

//构建油门设置数组。 (#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是一个可选参数。如果没有包含,将使用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;
     

}

答案 4 :(得分:1)

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

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

就像网站被slashdot效应所击中一样,其中许多只是将流量重定向,直到流量减少。