我刚刚读了这篇文章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/