非PHP环境下登录失败限流延迟设置及无sleep()防Bot登录延迟实现
不用sleep()实现登录失败后的延迟拦截方案
我太懂你这种卡壳的烦躁了——职业倦怠回来对着旧问题还是摸不着头脑,真的闹心。既然你已经搞定了失败尝试的数据库记录,那接下来的核心就是让客户端而非服务器来承担等待成本(这也是为啥不能用sleep()——它会占着服务器进程,反而给Bot送DoS机会),下面分应用层(PHP)和服务器层(Apache/.htaccess)给你具体方案:
一、PHP应用层:用HTTP响应头引导客户端等待
这是最灵活精准的方案,完全不需要sleep(),还能结合你已有的失败记录做动态延迟:
核心逻辑:
- 当用户/IP的失败登录次数超过阈值时,从数据库中计算出「下次允许登录的时间」
- 给客户端返回
429 Too Many Requests状态码,同时加上Retry-After响应头,明确告知需要等待的秒数 - 直接终止脚本,释放服务器进程
代码示例:
// 先从数据库获取当前IP的失败尝试记录(假设你已经有这个查询逻辑) $failedAttempts = getFailedLoginAttempts($_SERVER['REMOTE_ADDR']); $lastFailedTime = getLastFailedLoginTime($_SERVER['REMOTE_ADDR']); $threshold = 3; // 允许3次失败尝试 $baseWait = 5; // 第一次触发延迟的基础等待时间(秒) if ($failedAttempts >= $threshold) { // 用指数退避算法计算等待时间(失败次数越多,等待越久,比如5s→10s→20s...) $waitSeconds = $baseWait * pow(2, $failedAttempts - $threshold); // 计算下次允许登录的时间,防止客户端篡改本地时间绕过 $nextAllowedTime = time() + $waitSeconds; updateNextAllowedLoginTime($_SERVER['REMOTE_ADDR'], $nextAllowedTime); // 返回HTTP 429和重试头 header("HTTP/1.1 429 Too Many Requests"); header("Retry-After: $waitSeconds"); echo "登录失败次数过多,请 $waitSeconds 秒后再尝试"; exit; } // 下面是正常的登录验证逻辑...额外优化:
- 给前端返回等待时间,让前端直接禁用登录按钮对应秒数(比如用JS设置按钮disabled状态),合法用户体验更好
- 即使Bot无视
Retry-After头,下次请求时你依然可以通过数据库里的nextAllowedTime直接拒绝,完全不受影响
二、Apache服务器层:做基础速率限制(配合应用层更稳妥)
服务器层的限制适合做兜底,防止Bot在短时间内发起大量请求,减轻应用层的压力:
方法1:用mod_ratelimit限制登录接口的请求频率
在.htaccess中添加以下规则,限制同一个IP每分钟最多向login.php发起10次请求:
<Files "login.php"> # 启用速率限制 RatelimitEnable On # 设置速率:10次请求/分钟 RatelimitRate 10 requests/minute # 针对IP限制 RatelimitRemoteIP On </Files>
方法2:用mod_rewrite做更灵活的拦截
如果你需要做基础的请求次数拦截(服务器层无法直接判断登录是否失败,所以更适合做兜底限流):
RewriteEngine On # 限制1分钟内最多10次POST请求到login.php RewriteCond %{REQUEST_URI} ^/login.php$ RewriteCond %{REQUEST_METHOD} POST RewriteCond %{ENV:REDIRECT_STATUS} ^$ RewriteCond %{REMOTE_ADDR} ^(.*)$ RewriteCond %{ENV:RATELIMIT_%1} !^$ RewriteRule ^ - [R=429,L] RewriteCond %{REQUEST_URI} ^/login.php$ RewriteCond %{REQUEST_METHOD} POST RewriteCond %{ENV:REDIRECT_STATUS} ^$ RewriteCond %{REMOTE_ADDR} ^(.*)$ RewriteRule ^ - [E=RATELIMIT_%1:%{TIME_MINUTE},L]
三、关键注意点
- 绝对不要用sleep():它会让Apache进程一直被占用,Bot发起100个请求就会占100个进程,直接拖垮服务器
- 数据库记录要精准:一定要记录IP(如果是已登录用户可以记录用户ID)、失败时间、下次允许登录时间,防止被绕过
- 指数退避比固定延迟更有效:失败次数越多,等待时间翻倍,Bot的攻击成本会指数级上升
内容的提问来源于stack exchange,提问作者ArabianMaiden
相关产品推荐
相关产品推荐

