security - 如何在 PHP 中限制用户登录尝试

标签 security throttling honeypot

我刚刚读了这篇文章The definitive guide to form-based website authentication关于防止快速登录尝试。

最佳实践#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 将确保停止来自多个方面的攻击,并且普通网站用户不会因合法的失败登录尝试而遇到明显的延迟。

关于security - 如何在 PHP 中限制用户登录尝试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2090910/

相关文章:

security - 使用Acegi安全性以脚本级别登录Grails应用

c# - 为什么我无法在远程计算机上使用模拟打开文件?

sql - 基础表的特权是否自动传递给在该表上创建的任何 View ?

asp.net-mvc - 在 ASP.NET MVC 中实现请求限制的最佳方法?

captcha - Shopify 蜜 jar

c - 尝试用C语言构建一个SSH蜜 jar

java - 如何以编程方式创建数据库且注入(inject)安全?

node.js - 如何在node.js中使用 'limiter'

javascript - Throttle-debounce 的事件对象

javascript - 蜜 jar 实现