如何限制PHP中的用户登录尝试

我刚刚阅读这篇文章“防止快速登录尝试的基于表单的网站身份验证的权威指南”。

最佳做法#1:短时间延迟随失败尝试的次数而增加,如:

1次失败尝试=没有延迟
2次失败尝试= 2秒延迟
3次失败尝试= 4秒延迟
4次失败尝试= 8秒延迟
5次失败尝试= 16秒延迟
等等

DoS攻击这种方案将是非常不切实际的,但另一方面,可能具有破坏性,因为延迟呈指数级增长。

我很好奇我如何在PHP中为我的登录系统实现这样的功能?


您不能简单地通过将限制链接到单个IP或用户名来防止DoS攻击。 地狱,你甚至不能真正防止使用这种方法的快速登录尝试。

为什么? 由于攻击可以跨越多个IP和用户帐户,以绕过您的限制尝试。

我在其他地方看到过,理想情况下,您应该跟踪整个网站上所有失败的登录尝试,并将它们与时间戳相关联,或许:

CREATE TABLE failed_logins (
    id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(16) NOT NULL,
    ip_address INT(11) UNSIGNED NOT NULL,
    attempted DATETIME NOT NULL,
    INDEX `attempted_idx` (`attempted`)
) engine=InnoDB charset=UTF8;

有关ip_address字段的快速注释:您可以分别使用INET_ATON()和INET_NTOA()来存储数据并检索数据,这基本上等同于将IP地址转换为无符号整数并将其转换为无符号整数。

# example of insertion
INSERT INTO failed_logins SET username = 'example', ip_address = INET_ATON('192.168.0.1'), attempted = CURRENT_TIMESTAMP;
# example of selection
SELECT id, username, INET_NTOA(ip_address) AS ip_address, attempted;

根据给定时间内失败登录的总数(本例中为15分钟)确定某些延迟阈值。 您应该基于从failed_logins表中提取的统计数据,因为它会根据用户数量以及他们可以调用(并输入)其密码的数量随时间变化。


> 10 failed attempts = 1 second
> 20 failed attempts = 2 seconds
> 30 failed attempts = reCaptcha

在每次失败的登录尝试中查询表,以查找给定时间段内失败登录的次数,例如15分钟:


SELECT COUNT(1) AS failed FROM failed_logins WHERE attempted > DATE_SUB(NOW(), INTERVAL 15 minute);

如果在给定时间段内的尝试次数超过了您的限制,则强制执行限制或强制所有用户使用验证码(即reCaptcha),直到给定时间段内的失败尝试次数小于阈值。

// array of throttling
$throttle = array(10 => 1, 20 => 2, 30 => 'recaptcha');

// retrieve the latest failed login attempts
$sql = 'SELECT MAX(attempted) AS attempted FROM failed_logins';
$result = mysql_query($sql);
if (mysql_affected_rows($result) > 0) {
    $row = mysql_fetch_assoc($result);

    $latest_attempt = (int) date('U', strtotime($row['attempted']));

    // get the number of failed attempts
    $sql = 'SELECT COUNT(1) AS failed FROM failed_logins WHERE attempted > DATE_SUB(NOW(), INTERVAL 15 minute)';
    $result = mysql_query($sql);
    if (mysql_affected_rows($result) > 0) {
        // get the returned row
        $row = mysql_fetch_assoc($result);
        $failed_attempts = (int) $row['failed'];

        // assume the number of failed attempts was stored in $failed_attempts
        krsort($throttle);
        foreach ($throttle as $attempts => $delay) {
            if ($failed_attempts > $attempts) {
                // we need to throttle based on delay
                if (is_numeric($delay)) {
                    $remaining_delay = time() - $latest_attempt - $delay;
                    // output remaining delay
                    echo 'You must wait ' . $remaining_delay . ' seconds before your next login attempt';
                } else {
                    // code to display recaptcha on login form goes here
                }
                break;
            }
        }        
    }
}

在某个阈值使用reCaptcha将确保停止多个前端的攻击,并且正常的站点用户不会因为合法的失败登录尝试而遭受重大延迟。


您有三种基本方法:存储会话信息,存储Cookie信息或存储IP信息。

如果您使用会话信息,最终用户(攻击者)可能会强行调用新的会话,绕过您的策略,然后再次登录而不会延迟。 会话实现起来非常简单,只需将用户的最后一次已知登录时间存储在会话变量中,将其与当前时间相匹配,并确保延迟时间足够长。

如果你使用cookies,攻击者可以简单地拒绝cookie,总而言之,这实际上不是可行的。

如果您追踪IP地址,则需要以某种方式存储来自IP地址的登录尝试,最好是存储在数据库中。 当用户尝试登录时,只需更新您记录的IP列表。 您应该以合理的时间间隔清除此表,并转储一段时间内未激活的IP地址。 陷阱(总是有一个陷阱)是,有些用户最终可能会共享一个IP地址,而在边界条件下,您的延迟可能会对用户造成不良影响。 由于您正在跟踪登录失败,并且只有登录失败,所以这不应该导致太多的痛苦。


登录过程需要降低成功和失败登录的速度。 登录尝试本身不应该比大约1秒钟更快。 如果是这样,蛮力使用延迟知道尝试失败,因为成功比失败短。 然后,可以每秒评估更多组合。

每台机器的同时登录尝试次数需要由负载均衡器来限制。 最后,您只需跟踪多个用户/密码登录尝试是否重复使用了相同的用户或密码。 人类无法打字的速度超过每个微小约200字。 因此,连续或同时登录的尝试速度超过每个微小200个字词来自一组机器。 因此,这些可以安全地输入黑名单,因为它不是您的客户。 每台主机的黑名单时间不需要大于1秒。 这绝对不会给人类带来不便,但是无论是串联还是并联都可能造成混乱。

每秒一个组合的2 * 10 ^ 19个组合,在40亿个独立的IP地址上并行运行,将花费158年的时间作为搜索空间。 对于每个用户持续一天的攻击者数量为40亿,您需要一个完全随机的字母数字密码,最少9个位置。 考虑在通行短语中对用户进行至少13个位置的长度,1.7 * 10 ^ 20个组合的训练。

这种延迟会激发攻击者窃取你的密码散列文件,而不是蛮横地强制你的网站。 使用批准的,命名的散列技术。 一秒钟禁止整个互联网IP的人口,将限制并行攻击的效果,而不会让人感到惋惜。 最后,如果您的系统在一秒内允许超过1000次失败的登录尝试而没有对禁止系统做出响应,那么您的安全计划就有更大的问题需要解决。 首先修复自动回复。

链接地址: http://www.djcxy.com/p/3683.html

上一篇: How can I throttle user login attempts in PHP

下一篇: Securing Client Password on Client Machine