第03章:AI生成的限速配置,为什么没有生效?
第03章:AI生成的限速配置,为什么没有生效?
“你加了 limit_req_zone,但攻击者还是能每秒发送几百个请求——因为 limit_req 的位置放错了,或者 burst 设置让限速形同虚设。”
ℹ️ 版本说明:本章基于 Nginx 1.30.2 +
ngx_http_limit_req_module(内置模块)。
3.1 AI默认会生成什么
你让 AI 帮你配置 API 限速,它通常给你:
http {
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
server {
location /api/ {
limit_req zone=api burst=20;
proxy_pass http://127.0.0.1:8000;
}
}
}
这个配置的意图是:每个 IP 每秒最多10个请求,峰值允许20个(burst)。
但实际上,这个配置有两个问题:
burst=20没有nodelay:当请求超过速率时,Nginx 会把它们排队(最多排20个),而不是立刻拒绝。结果:攻击者可以每秒发送 20+10=30 个请求,全部最终都能通过(只是有延迟)。- 没有区分不同接口:登录接口(应该很严格)和普通 API(可以宽松)用同一个规则。
3.2 AI通常遗漏的4个坑
⚠️ 坑1:burst 和 nodelay 的混淆
limit_req zone=api burst=20; # 超速请求排队,最终都通过
limit_req zone=api burst=5 nodelay; # 超速请求立刻拒绝(429)
没有 nodelay 的 burst,是一个"缓冲区"——超出速率的请求会等待,但都会被处理。这不是真正的限速,而是"削峰"(延迟处理)。
对于防暴力破解的登录接口,你需要的是硬限速(超过立刻 429),而不是排队处理。
⚠️ 坑2:限速 zone 放在了错误的位置
http {
limit_req_zone ...; # 定义 zone,必须在 http 块
}
server {
limit_req zone=api; # 应用限速
location / {
limit_req zone=api; # 如果同时在 server 和 location 里设置,只有更精确的(location)生效
}
}
当 server 级别和 location 级别都有 limit_req 时,只有最精确的那个生效(location 优先)。AI 有时会在两个地方都加,但实际只有一个在工作。
⚠️ 坑3:用 $remote_addr 而不是 $binary_remote_addr
limit_req_zone $remote_addr zone=api:10m rate=10r/s; # 字符串形式,最多15字节
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; # 二进制形式,IPv4 4字节,IPv6 16字节
使用 $binary_remote_addr 可以节省大约 3-4 倍的内存,对于存储大量 IP 的 zone 来说有意义。AI 通常知道用 $binary_remote_addr,但不知道解释为什么。
⚠️ 坑4:没有 limit_req_status 自定义错误码
限速被触发时,Nginx 默认返回 503(Service Unavailable)。但 RFC 6585 定义了 429(Too Many Requests)专门用于限速。
客户端收到 503 会认为服务器崩溃了,应该收到 429 才知道是被限速了,可以稍后重试。
limit_req_status 429;
3.3 更好的提示词
提示词 P01:为不同接口配置分级限速
使用时机:API 服务需要对不同接口设置不同的限速规则
比默认多了什么:
- 不同接口不同规则(登录严格,普通 API 宽松)
- nodelay 控制
- 正确的错误码(429)
帮我为 Nginx 1.30.x 配置分级 API 限速。
接口类型和限速规则:
1. 登录/注册接口(/api/auth/login, /api/auth/register):
- 同一 IP,每分钟最多 5 次
- 超过立刻返回 429(硬限速,不排队)
2. 发送验证码接口(/api/auth/send-sms):
- 同一 IP,每分钟最多 2 次,每小时最多 10 次
- 注意:Nginx 的 limit_req_zone 可以同时应用多个 zone 吗?
3. 普通 API(/api/ 其他路径):
- 同一 IP,每秒最多 20 次
- 允许 burst=10(削峰,但超过 burst 立刻拒绝)
4. 公开接口(/health, /public/):
- 不限速
配置要求:
- 所有超速响应返回 429(不是默认的 503)
- 在响应头中包含 X-RateLimit-Limit 和 Retry-After(Nginx 原生支持吗?如果不支持告诉我)
- 每个 limit_req_zone 的内存大小合理计算(10m 可以存多少个 IP?)
基于 Nginx 1.30.2。
提示词 P02:基于用户 ID 的限速(已登录用户)
使用时机:对已认证用户按 user_id 限速,而不是按 IP
比默认多了什么:
- 从 JWT/Session 提取用户标识
- 未认证用户回退到 IP 限速
帮我配置基于用户 ID 的 Nginx 限速,而不是 IP。
场景:API 网关在 JWT Token 的 Header 里(Authorization: Bearer <token>)。我想按用户 ID 限速,防止单个用户滥用 API(而不是按 IP,因为企业用户可能共享 IP)。
方案分析:
1. Nginx 原生不能解析 JWT,能从 Header 里提取 user_id 吗?
2. 我能用哪个 Nginx 变量作为限速 key?
- 方案A:用 Authorization Header 的 hash 值(不精确,但不需要解析)
- 方案B:后端在响应里加 X-User-ID 头,Nginx 缓存并用于限速(复杂但精确)
- 方案C:在 Nginx 前面加一层 OpenResty/Lua 解析 JWT(需要额外组件)
3. 对于未携带 token 的请求,回退到 IP 限速
告诉我哪个方案最实际可行,给出对应的配置。
基于 Nginx 1.30.2(开源版,不含 Lua)。
提示词 P03:验证限速配置是否真的生效
使用时机:配置完限速后,需要验证配置是否按预期工作
比默认多了什么:
- 压测验证
- 查看 Nginx 内部计数器
- 常见失效原因检查
帮我写验证 Nginx 限速配置是否正确生效的测试方法。
我配置的规则:每个 IP 每秒最多 10 个请求,burst=5 nodelay
验证需要:
1. 用 ab(Apache Benchmark)或 hey 工具发送突发请求,验证:
- 前 10 个在1秒内处理
- 第 11-15 个(burst 内):立刻处理(nodelay)
- 第 16+ 个:立刻返回 429
- 给我具体的 ab 命令
2. 用 curl 循环测试(更直观):
- 1秒内发10次,全部 200
- 1秒内发20次,后10次应该 429
- 给我 Bash 脚本
3. 在 Nginx 日志中找限速触发的记录:
- 限速触发时 Nginx 日志的格式
- grep 命令找出所有被限速的请求
4. 检查限速没有生效的常见原因:
- 配置文件重载了吗(nginx -s reload)?
- 配置在 server 还是 location 级别(哪个生效)?
- burst 和 nodelay 是否同时配置了?
- zone 内存大小是否足够(10m 不够会自动驱逐)
基于 Nginx 1.30.2。
3.4 验收清单
| 检查项 | 验证方法 | AI辅助 |
|---|---|---|
| 限速实际生效(非排队) | 1秒内超量请求收到 429 | 用 P03 提示词写验证脚本 |
| 限速状态码是 429 | 超速请求响应码是 429,不是 503 | 让 AI 添加 limit_req_status 429 |
| 不同接口有不同规则 | 登录接口更严格 | 用 P01 提示词配置分级规则 |
| limit_req_zone 在 http 块 | nginx -t 无错误 |
让 AI 检查配置位置 |
| burst 和 nodelay 正确配置 | 代码审查 burst/nodelay 参数 | 让 AI 解释当前配置行为 |
| 限速日志可查 | grep "limiting" /var/log/nginx/error.log |
让 AI 调整日志级别 |
3.5 本章小结
如果你只记一件事:为登录接口的 limit_req 添加 nodelay 参数。没有 nodelay,你的"限速"实际上是"排队",攻击者的请求最终都能通过。
Nginx 限速的三个关键决策:
- burst + nodelay:保护关键接口(登录、短信)用
nodelay;普通 API 可以不加(让峰值请求排队处理) - 分接口分规则:登录接口每分钟5次,普通 API 每秒20次——一刀切的规则要么太严(影响正常用户)要么太宽(无法防攻击)
- 429 而不是 503:客户端需要知道是被限速了,而不是服务器崩溃了
→ 第4章:AI帮我配置了负载均衡,但健康检查在哪?