跳转至

abuse-guard: 自动禁止滥用客户端通过错误响应率 (404/403/5xx)

需要 GetPageSpeed NGINX Extras 订阅的专业计划(或更高版本)。

安装

您可以在任何基于 RHEL 的发行版中安装此模块,包括但不限于:

  • RedHat Enterprise Linux 7、8、9 和 10
  • CentOS 7、8、9
  • AlmaLinux 8、9
  • Rocky Linux 8、9
  • Amazon Linux 2 和 Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-abuse-guard
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-abuse-guard

通过在 /etc/nginx/nginx.conf 顶部添加以下内容来启用模块:

load_module modules/ngx_http_abuse_guard_module.so;

本文档描述了 nginx-module-abuse-guard v1.1.0 于 2026 年 7 月 09 日发布。


您的错误日志是一个忏悔。Abuse Guard 实时读取它并将滥用者拒之门外。

每个扫描器、模糊测试器和凭证填充机器人都会留下相同的指纹: 一串 404 寻找隐藏路径,403 敲打锁住的门,失败的请求接连不断。Abuse Guard 监视您的服务器 实际返回 的状态码,识别出流量大部分是失败的客户端,并将它们锁定——在 NGINX 工作进程内部,在请求本身中,几微秒内决定。没有边车。没有日志传输器。没有脚本层。只有编译的 C 在执行一项工作时表现得极为出色。

规格表

触发器 每个客户端的错误响应率(默认是 403/404
动作 定时锁定——在固定时间窗口内的硬性禁止,而不是限流
决策点 NGINX 预访问阶段,在任何处理程序或上游运行之前
内存模型 每个客户端固定字节,与阈值无关 → 适用于僵尸网络规模
舰队模式 可选的通过 Redis / Valkey 在节点间复制禁止
耐久性 可选的磁盘禁止快照,能够在重载和重启后存活
占用空间 一个自包含模块;默认情况下零运行时依赖
平台 RHEL / AlmaLinux / Rocky / CentOS Stream / Oracle / Amazon Linux
##

它解决的问题

合法访客几乎从不产生错误的突发。滥用者几乎只产生这些——这种不对称性就是整个游戏。一个漏洞扫描器在您的树上行走是一堵 404 的墙。一个机器人在管理端点上捣鼓是一堵 403 的墙。一次暴力破解运行是一堵失败的墙。

限流器将该流量视为其他流量:它通过请求量减慢 每一个人 的速度,并让违法者在一放松的瞬间重新进入。Abuse Guard 则相反。它完全忽略行为良好的流量,并将其唯一的响应——一个真实的、时间限制的禁止——保留给那些因错误而定义的客户端。

使用限流器来塑造负载。使用 Abuse Guard 来驱逐滥用。

如何决定禁止

三个动态部分,全部在工作进程内部:

1 · 每个客户端的泄漏分数。 每个客户端身份在共享内存中携带一个小数字。每个匹配的错误都会增加它;分数以 threshold ÷ interval 每秒持续流失。一次短暂的、急剧的突发会将其推过界;缓慢的涓涓细流则永远不会。至关重要的是,这个分数是 一个固定大小的记录,无论您将阈值设置得多高——因此单个区域可以轻松跟踪僵尸网络向您抛出的数万个不同源地址。

2 · 一个严格的截止日期。 一旦分数超过您的阈值,客户端就会获得一个 blocked_until 时间戳。在此之前,它就简单地消失了——每个请求在 预访问阶段 被拒绝,在 NGINX 花费一个周期进行路由、文件或上游之前。拒绝是可能的最低成本结果。

3 · 一个隐私正确的拒绝。 被禁止的客户端会收到 429 Too Many Requests (您选择的代码),并标记为没有共享缓存可以存储它并将一个客户端的惩罚提供给另一个客户端,同时带有一个 Retry-After 告诉诚实的客户端何时返回。

身份被折叠成一个固定大小的摘要,因此在像 $request_uri 或一个头部这样的较大内容上进行键控的内存开销与在 IP 上进行键控的开销完全相同。

在一分钟内上线

Abuse Guard 作为一个预编译、签名的模块从 GetPageSpeed 仓库中提供——直接放入,无需构建工具链。

sudo yum -y install https://extras.getpagespeed.com/release-latest.rpm
sudo yum -y install nginx-module-abuse-guard

连接起来:

load_module modules/ngx_http_abuse_guard_module.so;

http {
    abuse_guard_zone zone=clients:10m;     # 一个共享内存区域

    server {
        location / {
            abuse_guard zone=clients;      # 在此强制执行
        }
    }
}
sudo nginx -t && sudo systemctl reload nginx

这些默认设置禁止任何在 5 分钟窗口内返回 100 个 403/404 响应的 IP,禁止一个小时。 可以收紧或放宽下面的每个数字。

配置

Abuse Guard 有四个指令。第一个声明一个策略;其余的应用它、豁免某些人,并(可选地)在机器间共享它。

声明一个策略 — abuse_guard_zone

一个 http 级别的指令。 它划分出一个共享内存区域并设置管理它的策略。您可以设置任意数量的参数——区域的名称和大小是您必须提供的唯一内容;合理的默认值填充其余部分(下面显示的值正是这些默认值)。

abuse_guard_zone  zone=clients:10m             名称 + 大小(唯一必须的)
                  key=$binary_remote_addr      谁是“一个客户端”
                  statuses=403,404             哪些响应计入错误
                  interval=300s                评分窗口
                  threshold=100                在该窗口内的错误  禁止
                  block=60m;                   禁止持续多长时间

zone=clients:10m 是策略的身份和预算:您在 abuse_guard 中引用的名称,以及共享内存的大小。大约 10 MB 可以跟踪大约十万个活跃客户端。

其他所有内容都是可选的调优:

  • key — 定义单个客户端的表达式。任何 NGINX 变量; 默认的 $binary_remote_addr 以源 IP 为键。一个键为空的请求会被完全跳过(在下面的 map 中很方便)。
  • statuses — 计入错误的响应代码:单个代码、范围或混合,例如 statuses=401,403,404,500-599。默认值为 403,404
  • interval — 分数衰减的窗口(默认 300s)。在此窗口内的突发会触发禁止;缓慢的涓涓细流则不会积累。
  • threshold — 在该窗口内超过的错误数量,最多 1024(默认 100)。
  • block — 被触发的客户端保持锁定的时间(默认 60m)。
  • inactive — 在内存中闲置的客户端在被回收之前停留的时间(默认 max(1h, interval, block);任何显式值必须至少与 intervalblock 一样大)。
  • redison 以在整个集群中复制该区域的禁止 (见下文);默认是 off
  • persist — 一个文件路径,用于快照禁止,以便它们在重启后存活。
  • persist_interval — 多久重写一次快照(默认 5s)。
  • persist_secret — 一个十六进制密钥,用于使用 HMAC-SHA256 签名快照,因此篡改的文件会被拒绝而不是加载。

为什么默认情况下不包括 5xx 服务器错误通常是 一方的 行为,计入它会让一个不稳定的后端使无辜的访客被禁止。 仅在您故意想要对触发服务器错误的客户端采取行动时,添加 statuses=403,404,500-599

应用它 — abuse_guard

有效于 httpserverlocation,因此您可以保护整个网站或仅保护吸引滥用的端点。命名区域以启用它;在嵌套作用域中写 abuse_guard off; 以将其关闭。

location /wp-login.php {
    abuse_guard zone=clients status=429 log_level=warn;
}
  • zone — 适用于此处的区域(在上面声明)。
  • status — 被禁止的客户端收到的代码,范围在 400599 (默认 429)。
  • dry_runon 以观察而不强制执行:判决被记录但不写入禁止。默认关闭。
  • log_level — 记录每个决策的响亮程度:infonotice(默认)、warnerror

大胆推出 dry_run=on 它记录每个它 发出的禁止,而不触及状态,因此您可以根据实时流量校准阈值——即使是在同一区域的强制执行位置旁边——然后实时切换。

豁免好人 — abuse_guard_allow

上下文: http · server · location · 可重复,向下继承。

abuse_guard_allow 127.0.0.0/8;
abuse_guard_allow 10.0.0.0/8 192.168.0.0/16;

列出的客户端永远不会被计入,也永远不会被禁止。匹配基于真实的连接地址,因此它与 realip 协作。这也是您保护 经过验证的搜索爬虫 的方式:允许已发布的 Googlebot / Bingbot 范围,以便一个在过时 URL 上磨蹭的机器人(并累积 404)永远不会被捕获。

在整个集群中共享禁止 — abuse_guard_redis

上下文: http

abuse_guard_redis host=10.0.0.5 password=… ;   # tls://host 用于 TLS
abuse_guard_zone  zone=clients:10m redis=on;

将每个节点指向一个 Redis 或 Valkey,切换 redis=on,在任何机器上获得的禁止将传播到所有机器。默认值:port=6379db=0prefix=ag_timeout=100ms。它如何保持快速是下一部分。

SELinux: 在强制系统(RHEL、Rocky、AlmaLinux)上,内核会阻止 NGINX 打开与 Redis 的连接,直到您允许它一次—— setsebool -P httpd_can_network_connect 1。跳过此步骤,复制将静默无效,而本地强制执行将正常进行。

一次禁止,所有节点——不减慢单个请求

在负载均衡器后,按服务器禁止是戏剧:攻击者只需落在不同的节点上。Abuse Guard 关闭了这个差距 而不将 Redis 放在请求路径中。

每个节点在本地决定并在本地计数。一旦它发出禁止,它会将这一事实广播到集群并记录一个持久副本。每个其他节点在毫秒内导入它,任何离线的节点在重新连接时会进行协调。因为执行始终从每个节点自己的内存状态中提供,访客的请求从不等待网络往返——集群的唯一成本是一个新禁止的攻击者在稍后被全队拒绝,而不是立即。

在这里,Redis 是一个单向警报,而不是每个请求都查询的共享账本——因此,缓慢或缺失的 Redis 永远不会给您的流量增加延迟。将其运行在私有网络上并视为特权:任何可以写入它的内容都可以发出禁止。

超过重启的禁止

将一个区域指向一个文件,活动禁止将在间隔内快照并在启动时恢复,因此重载或重启不会给每个攻击者提供一个新起点。

abuse_guard_zone zone=clients:10m
                 persist=/var/lib/nginx/abuse_guard/clients.state
                 persist_secret=00112233445566778899aabbccddeeff;

快照经过完整性检查,写入方式使崩溃永远不会留下撕裂的文件,并且——使用 persist_secret——经过加密签名,因此篡改的文件会被拒绝而不是信任。保持该目录仅对工作用户可读。

查看它所做的所有决策

三个变量将 Abuse Guard 的判决暴露给您的日志和配置:

变量
$abuse_guard_status BYPASSED · PASSED · COUNTED · BLOCKED · DRY_RUN
$abuse_guard_count 当前归因于该客户端的错误数量。
$abuse_guard_blocked_until 禁止解除的 Unix 时间,或 0
log_format guard '$remote_addr "$request" $status '
                 'guard=$abuse_guard_status count=$abuse_guard_count';

在 CDN 或代理后进行键控? 永远不要信任原始的 X-Forwarded-For。让 realip 首先解析真实客户端,然后在 $binary_remote_addr 上进行键控:

set_real_ip_from 10.0.0.0/8;
real_ip_header   X-Forwarded-For;
real_ip_recursive on;

需要每个请求的豁免逻辑?任何 key 解析为空字符串的请求将被忽略——因此一个 map 让您可以,例如,通过 IP 跟踪匿名访客,同时不触及经过身份验证的用户。

旨在在生产环境中值得信赖

Abuse Guard 的标准远高于“它可以编译”。每次更改都经过 AddressSanitizer、UndefinedBehaviorSanitizer、Valgrind、静态分析和对其解析器及磁盘格式的持续模糊测试的考验。其可选依赖项——集群和签名快照——是设计上的尽力而为:如果 Redis 或磁盘出现问题,执行将安静地继续来自本地内存。 您的流量永远不会被依赖项所挟持。

获取 Abuse Guard

Abuse Guard 是来自 GetPageSpeed LLC 的商业 NGINX 模块,通过 GetPageSpeed 订阅提供持续的更新和支持。

© GetPageSpeed LLC. 保留所有权利。