元数据
| id | sms-api-rate-limit | 收录 | 2026-08-29 |
|---|---|---|---|
| 问题域 | 安全与治理 | 主题分组 | 权限与安全 |
| 适用工具 | nginx · 外部工具 | ||
症状
短信接口被脚本/恶意流量狂刷:短时间内大量请求、短信费用飙升、接口被打垮;泛化到任意业务接口——同一 IP/同一手机号高频请求、代理 IP 池轮换刷量、验证码接口被撞库。
原因
接口没有频率限制与黑名单:短信/验证码接口天然可被无限调用(无频次、无来源限制),一次被刷就是真金白银损失;紧急止损手段(熔断/降级/黑名单/限流)缺失或配置无效(见验证证据:`limit_req` 与 `return` 同 location 时被短路,配置"看似有"实则无)。
解法
1. **紧急止损(黄金 30 分钟)**:配置中心把短信接口切"测试模式"(返回成功但不真发)或直接熔断;Nginx 层封禁异常 IP(`deny`,实测 403);网关层开全局限流;无效则临时关停短信功能保核心业务。
2. **Nginx 频率限制(实测生效形态)**:
```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` 层。
3. **业务层防护**:手机号频次限制(Redis `INCR`+`EXPIRE`,过期自动重置);布隆过滤器快速过滤无效/风险手机号(千万级 12MB);设备指纹/行为风控;API 签名。本机无 redis-server 与 docker daemon,未实测(如实标注)。
4. **监控复盘**:按 IP/手机号/设备统计请求量基线,异常自动告警;新风控规则灰度发布。
验证证据
- 本地实测(2026-08-29,nginx/1.28.3 nginx-light + python3,纯本地零网络):
1. 对照:无限流接口 15 连发全 200。
2. `limit_req zone=min rate=2r/s` + 静态文件:15 连发 = 1×200 + 14×503,错误日志记录 `limiting requests, excess: 0.974 by zone "min"`。
3. `limit_req rate=2r/s` + `proxy_pass` 反代:15 连发 = 1×200 + 14×503(生产形态正常生效)。
4. `deny 127.0.0.1`:请求 403,日志 `access forbidden by rule`。
5. **坑**:`limit_req + return 200` 同 location 连发全 200、日志无记录;`deny + return` 同样失效——`return` 短路 preaccess/access 阶段(第一版配置实测发现,修正后才有 2/3/4 的结果)。
- Redis/Lua 令牌桶、布隆过滤器:未实测(本机无 redis-server;Docker daemon 未运行,镜像拉取受限)。
- 实测复现日志(2026-08-29)
来源与证据
素材来源:https://www.cnblogs.com/zrui-xyu/p/22612063
验证证据:Evidence details kept locally (2026-08-29)