快速修复
# 一键:nginx 层加 IP 限流(http 块加 zone,location 内启用;超限返回 503)
# http 块:limit_req_zone $binary_remote_addr zone=sms:10m rate=5r/s;
# location 内:limit_req zone=sms burst=10 nodelay;
burst = 突发桶容量,nodelay = 超限立即拒绝;默认拒绝 503,可 limit_req_status 429 改 429。
你会遇到什么
短信接口被脚本/恶意流量狂刷:短时间内大量请求、短信费用飙升、接口被打垮。泛化到任意业务接口就是:同一 IP/同一手机号高频请求、代理 IP 池轮换刷量、验证码接口被撞库。一次被刷就是真金白银损失。
本文路径:快速修复(30 秒一段命令)→ 一步步排查(可跳读)→ 原理与变体(症状/原因/证据)。赶时间直接跳到「快速修复」。
为什么会这样
接口没有频率限制与黑名单:短信/验证码接口天然可被无限调用(无频次、无来源限制)。紧急止损手段(熔断/降级/黑名单/限流)缺失或配置无效——实测发现 limit_req 与 return 写在同一 location 时被短路,配置"看似有"实则无。
| 防护层 | 手段 | 实测状态 |
|---|---|---|
| 紧急止损 | 测试模式/熔断、Nginx deny、全局限流 | ✅ nginx deny 实测 403 |
| Nginx 限流 | limit_req_zone + limit_req | ✅ 静态/反代形态实测生效(503) |
| 业务层 | Redis 频次、布隆过滤器、设备指纹 | ⏳ 本机无 redis/docker,未实测 |
| 监控复盘 | 请求量基线 + 异常告警 | 上线后长期动作 |
短信/验证码接口被刷的本质是「无状态接口 + 无频次约束」:接口本身不记调用来源与次数,攻击者可以无限调用(撞库/骚扰/刷量),而成本由你承担。防护手段的「配置无效」是独立陷阱:nginx 的 limit_req 与 return 写在同一 location 时,return 直接短路后续指令——配置「看似有」实则无,这是实测复现的坑。
确定性推论:先验证防护真的生效(实测:nginx deny 403、limit_req 503),不验证的配置等于没有;防护分三层——网络层(nginx deny/限流,可立即上)、业务层(Redis 频次/设备指纹,需依赖)、监控层(基线+告警,长期);紧急止损用测试模式/熔断最直接(先止血再补防护);判断路径:被刷先确认「防护是否真的返回预期状态码」,再谈策略。
一步步来
1. 紧急止损(黄金 30 分钟) — 必做
配置中心把短信接口切"测试模式"(返回成功但不真发)或直接熔断;Nginx 层封禁异常 IP(deny,实测 403);无效则临时关停短信功能保核心业务。
2. Nginx 频率限制(实测生效形态) — 必做
http 块定义 zone:
limit_req_zone $binary_remote_addr zone=sms:10m rate=5r/s;
location 内启用(反代/静态文件形态均实测生效):
limit_req zone=sms burst=10 nodelay;
3. 业务层防护 — 必做
手机号频次限制(Redis INCR+EXPIRE,过期自动重置);布隆过滤器快速过滤无效/风险手机号(千万级 12MB);设备指纹/行为风控;API 签名。(本机无 redis-server 与 docker daemon,未实测,如实标注。)
4. 监控复盘 — 必做
按 IP/手机号/设备统计请求量基线,异常自动告警;新风控规则灰度发布。
怎么确认修好了
压测断言(实测输出形态:限流 15 连发):
curl 连发 15 次
→ 1×200 + 14×503(rate=2r/s 静态文件形态)
→ 错误日志:limiting requests, excess: 0.974 by zone "min"
deny 127.0.0.1 后请求 → 403(日志 access forbidden by rule)。
其它环境的表现
| 环境 | 说明 |
|---|---|
| 静态文件形态 | limit_req 实测生效:1×200 + 14×503 |
| proxy_pass 反代形态 | 生产形态实测生效:1×200 + 14×503 |
| deny + return 同 location | 实测失效(return 短路 preaccess/access 阶段) |
| limit_req + return 同 location | 实测失效(连发全 200、日志无记录)——文章未写的坑 |
| 业务层 | Redis 令牌桶/布隆过滤器未实测(无 redis-server / docker daemon) |
症状
短信接口被脚本/恶意流量狂刷:短时间内大量请求、短信费用飙升、接口被打垮;泛化到任意业务接口——同一 IP/同一手机号高频请求、代理 IP 池轮换刷量、验证码接口被撞库。
原因
接口没有频率限制与黑名单:短信/验证码接口天然可被无限调用(无频次、无来源限制),一次被刷就是真金白银损失;紧急止损手段(熔断/降级/黑名单/限流)缺失或配置无效(见验证证据:limit_req 与 return 同 location 时被短路,配置"看似有"实则无)。
解法
- 紧急止损(黄金 30 分钟):配置中心把短信接口切"测试模式"(返回成功但不真发)或直接熔断;Nginx 层封禁异常 IP(
deny,实测 403);网关层开全局限流;无效则临时关停短信功能保核心业务。 - Nginx 频率限制(实测生效形态):
limit_req_zone $binary_remote_addr zone=sms:10m rate=5r/s; # http 块
# location 内(反代/静态文件形态均实测生效,超限返回 503):
limit_req zone=sms burst=10 nodelay;
burst= 突发桶容量,nodelay= 超限立即拒绝;默认拒绝状态码 503(可limit_req_status 429改 429)。- 实测坑(文章未写):
limit_req/deny与return写在同一个 location 里不生效——return在 rewrite 阶段终止请求,跳过 preaccess/access 阶段;location = /api/sms/send { limit_req ...; return 200 "ok"; }这类配置等于无限流。接口必须走静态文件/proxy_pass反代形态,或把限流放server层。
- 业务层防护:手机号频次限制(Redis
INCR+EXPIRE,过期自动重置);布隆过滤器快速过滤无效/风险手机号(千万级 12MB);设备指纹/行为风控;API 签名。本机无 redis-server 与 docker daemon,未实测(如实标注)。 - 监控复盘:按 IP/手机号/设备统计请求量基线,异常自动告警;新风控规则灰度发布。
验证证据
- 本地实测(2026-08-29,nginx/1.28.3 nginx-light + python3,纯本地零网络):
- 对照:无限流接口 15 连发全 200。
limit_req zone=min rate=2r/s+ 静态文件:15 连发 = 1×200 + 14×503,错误日志记录limiting requests, excess: 0.974 by zone "min"。limit_req rate=2r/s+proxy_pass反代:15 连发 = 1×200 + 14×503(生产形态正常生效)。deny 127.0.0.1:请求 403,日志access forbidden by rule。- 坑:
limit_req + return 200同 location 连发全 200、日志无记录;deny + return同样失效——return短路 preaccess/access 阶段(第一版配置实测发现,修正后才有 2/3/4 的结果)。
- Redis/Lua 令牌桶、布隆过滤器:未实测(本机无 redis-server;Docker daemon 未运行,镜像拉取受限)。
- 实测复现日志(2026-08-29)
适用工具 (1)
本问题方案已挂到下列工具的方案页——从工具页也能回到这里,双向可达。
nginx · 外部工具来源与证据
← 安全与治理 问题域 | 问题货架 | 遇到其它问题?去 问题空间 提交求助卡