如何在 PHP 中限制用户登录尝试 [英] How can I throttle user login attempts in PHP

查看:80
本文介绍了如何在 PHP 中限制用户登录尝试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

最佳实践#1:随着失败尝试次数的增加而增加的短时间延迟,例如:

Best practice #1: A short time delay that increases with the number of failed attempts, like:

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

1 failed attempt = no delay
2 failed attempts = 2 sec delay
3 failed attempts = 4 sec delay
4 failed attempts = 8 sec delay
5 failed attempts = 16 sec delay
etc.

DoS 攻击此方案是非常不切实际的,但另一方面,由于延迟呈指数增长,因此具有潜在的破坏性.

DoS attacking this scheme would be very impractical, but on the other hand, potentially devastating, since the delay increases exponentially.

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

推荐答案

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

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

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

I have seen posted elsewhere that ideally you should be tracking all failed login attempts across the site and associating them to a timestamp, perhaps:

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 地址转换为无符号整数.

A quick note on the ip_address field: You can store the data and retrieve the data, respectively, with INET_ATON() and INET_NTOA() which essentially equate to converting an ip address to and from an unsigned integer.

# 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 表中提取的统计数据,因为它会随着时间的推移根据用户数量以及他们中有多少人可以回忆(和输入)他们的密码.

Decide on certain delay thresholds based on the overall number of failed logins in a given amount of time (15 minutes in this example). You should base this on statistical data pulled from your failed_logins table as it will change over time based on the number of users and how many of them can recall (and type) their password.

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

<小时>

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


Query the table on every failed login attempt to find the number of failed logins for a given period of time, say 15 minutes:

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

<小时>

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


If the number of attempts over the given period of time is over your limit, either enforce throttling or force all user's to use a captcha (i.e. reCaptcha) until the number of failed attempts over the given time period is less than the threshold.

// 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 将确保阻止来自多个方面的攻击,并且正常站点用户不会因合法的失败登录尝试而经历显着延迟.

Using reCaptcha at a certain threshold would ensure that an attack from multiple fronts would be stopped and normal site users would not experience a significant delay for legitimate failed login attempts.

这篇关于如何在 PHP 中限制用户登录尝试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆