尝试过多后如何延迟登录尝试(PHP)

时间:2009-05-20 07:51:00

标签: php login-attempts

我正在开发一个用PHP构建的相当大的网站,可能会有很多用户。我正在研究一种保护登录屏幕免受自动尝试的方法。我已经在注册表中加入了CAPTCHA检查,但希望更多地加强网站。

我知道StackOverflow上有类似的问题,我知道我能够自己实现这一点(存储登录尝试及其在数据库中的时间),但我不喜欢这条路径:

  • 从概念上讲,我认为这种逻辑属于Web服务器/基础架构级别,而不属于应用程序级别。我不喜欢在我的应用程序中使用这种逻辑和复杂性
  • 我担心性能,特别是在数据库级别。
  • 我很懒,很好,不想从头开始构建这样的通用实用程序

任何建议都表示赞赏,我认为我特别想找到某种可以做到这一点的Apache模块。我的平台是PHP5(使用CodeIgniter),Apache2,MySQL 5.

3 个答案:

答案 0 :(得分:16)

更新:不要使用sleep()进行速率限制!这根本没有意义。我手边没有更好的解决方案。


在登录尝试失败后,只有sleep(1);才是一个良好的开端 - 易于实现,几乎没有错误。

1秒对于人类来说并不多(特别是因为人类的登录尝试经常不会失败),但是1秒/尝试暴力......懒散!字典攻击可能是另一个问题,但它在同一个域中。

如果攻击者也开始也可以通过连接来规避这种情况,那么你就会遇到一种DOS攻击。问题解决了(但现在你有另一个问题)。

你应该考虑的一些事情:

  • 如果您基于每个IP锁定帐户,则私有网络可能会出现问题。
  • 如果您以用户名为基础锁定帐户,则可能再次使用已知用户名进行拒绝服务攻击
  • 以IP /用户名为基础(其中用户名是被攻击者)可以更好地工作

我的建议: 完全锁定是不可取的(DOS),因此更好的选择是:从唯一的IP计算某个用户名的登录尝试。你可以用一个简单的表failed_logins: IP/username/failed_attempts

来做到这一点

如果登录失败,则wait(failed_attempts);秒。每隔xx分钟,运行一个将failed_logins:failed_attempts减少一个的cron脚本。

抱歉,我无法提供预制解决方案,但实施起来应该是微不足道的。

好的,好的。这是伪代码:

<?php
$login_success = tryToLogIn($username, $password);

if (!$login_success) {
    // some kind of unique hash
    $ipusr = getUserIP() . $username;

    DB:update('INSERT INTO failed_logins (ip_usr, failed_attempts) VALUES (:ipusr, 1) ON DUPLICATE KEY UPDATE failed_logins SET failed_attempts = failed_attempts+1 WHERE ip_usr=:ipusr', array((':ipusr' => $ipusr));

    $failed_attempts = DB:selectCell('SELECT failed_attempts WHERE ip_usr=:ipusr', array(':ipusr' => $ipusr));

    sleep($failed_attempts);
    redirect('/login', array('errorMessage' => 'login-fail! ur doin it rong!'));
}
?>

免责声明:这可能在某些地区无效。我听到的最后一件事是在亚洲有一个整个国家NATed(也是,他们都知道功夫)。

答案 1 :(得分:2)

一个非常虚拟的未经测试的例子,但我认为,你会在这里找到主要的想法。)

if ($unlockTime && (time() > $unlockTime))
{
    query("UPDATE users SET login_attempts = 0, unlocktime = 0 ... ");
}
else
{
   die ('Your account is temporary locked. Reason: too much wrong login attempts.');
}
if (!$logged_in)
{
    $loginAttempts++;
    $unlocktime = 0;
    if ($loginAttempts > MAX_LOGIN_ATTEMPTS) 
    {
        $unlockTime = time() + LOCK_TIMEOUT;
    }
    query("UPDATE users SET login_attempts = $loginAttempts, unlocktime = $unlocktime ... ");
}

对不起的错误 - 我在几秒钟内写了广告没有测试... 你可以通过IP,昵称,session_id等来做同样的事情......

答案 2 :(得分:-3)

为什么你不等待“加强”和“缩放”你的应用程序直到你真的遇到这个问题?最有可能的情况是应用程序永远不会有“很多用户”。这听起来像是对我的过早优化,需要避免的事情。

  • 一旦你机器人滥用,就加强注册。我实际上删除验证码,直到你开始获取&gt; 1000次注册/天。
  • 一旦遇到性能问题,请通过修复真正的瓶颈来提高性能。