You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

非PHP环境下登录失败限流延迟设置及无sleep()防Bot登录延迟实现

不用sleep()实现登录失败后的延迟拦截方案

我太懂你这种卡壳的烦躁了——职业倦怠回来对着旧问题还是摸不着头脑,真的闹心。既然你已经搞定了失败尝试的数据库记录,那接下来的核心就是让客户端而非服务器来承担等待成本(这也是为啥不能用sleep()——它会占着服务器进程,反而给Bot送DoS机会),下面分应用层(PHP)和服务器层(Apache/.htaccess)给你具体方案:

一、PHP应用层:用HTTP响应头引导客户端等待

这是最灵活精准的方案,完全不需要sleep(),还能结合你已有的失败记录做动态延迟:

  1. 核心逻辑:

    • 当用户/IP的失败登录次数超过阈值时,从数据库中计算出「下次允许登录的时间」
    • 给客户端返回429 Too Many Requests状态码,同时加上Retry-After响应头,明确告知需要等待的秒数
    • 直接终止脚本,释放服务器进程
  2. 代码示例:

    // 先从数据库获取当前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;
    }
    
    // 下面是正常的登录验证逻辑...
    
  3. 额外优化:

    • 给前端返回等待时间,让前端直接禁用登录按钮对应秒数(比如用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 09:17:14