最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
服务器遭 CC 攻击瘫痪?TP6.0 Nginx 层限流与应用层黑名单拦截【安防】
时间:2026-07-27 08:06:54 编辑:袖梨 来源:一聚教程网
TP6.0自身不提供IP级限流能力,真正扛住CC攻击的是Nginx的limit_req和limit_conn;应用层黑名单仅作补漏,因TP6.0拦截已消耗PHP资源,而Nginx在请求进入应用层前毫秒级拒绝。
直接说结论:TP6.0 自身不提供 IP 级限流能力,真正扛住 CC 攻击的必须是 Nginx 层的 limit_req 和 limit_conn;应用层黑名单只能补漏,不能当主力。
为什么 TP6.0 不能替代 Nginx 做限流?
ThinkPHP6.0 的中间件、行为或路由拦截都在 PHP 进程里执行,请求已经进来了、CGI 已启动、内存已分配、数据库连接可能已建立。这时候再拦,CPU 和连接资源早被耗光——CC 攻击打的就是这个时间差。
Nginx 的 limit_req 在 TCP 握手完成、HTTP 头解析后、但尚未转发给 PHP-FPM 前就做判断,毫秒级响应,不进应用层,不触发任何 PHP 逻辑。
- TP6.0 中间件拦截一个请求 ≈ 5–20ms(含 autoload、路由匹配、中间件链)
- Nginx
limit_req拒绝一个请求 ≈ 0.02ms(纯内存查表+计数) - 被 TP6.0 拦下的请求,仍会占用一个 PHP-FPM worker 进程和一次 CGI 调用
Nginx 配置必须写对的三个关键点
很多配置看似生效,压测一跑就崩,问题常出在 zone 定义位置、key 选择和 burst/nodelay 组合上。
-
limit_req_zone必须写在http块顶层,不能放在server或location里,否则 reload 会报错“invalid number of arguments” - 用
$binary_remote_addr而不是$remote_addr:前者二进制压缩,1M 内存可存约 16000 个 IP;后者字符串存储,同样内存只存约 4000 个,容易爆 zone -
burst=5 nodelay是生产推荐组合:允许 5 个突发请求立即通过(防误杀),超了直接返回503 Service Temporarily Unavailable;若只写burst=5不加nodelay,Nginx 会排队延迟处理,攻击者反而能靠长连接耗尽 worker
TP6.0 应用层黑名单只适合做“二次过滤”
它解决不了流量洪峰,但能干几件 Nginx 做不了的事:识别登录态用户、关联业务行为(如 1 小时内下单 100 次)、结合 Redis 实时封禁、记录到审计日志。前提是——请求得先活过 Nginx 这关。
- 在 TP6.0 的全局中间件里读
$_SERVER['REMOTE_ADDR'],查 Redis 黑名单(SETNX+EXPIRE) - 不要用数据库查黑名单,TP6.0 默认没开查询缓存,每次请求都连 DB,等于自己造了个新瓶颈
- 封禁动作建议返回
403 Forbidden并记录access.log,方便 Fail2Ban 后续抓日志自动封 IP - 注意 CDN 场景:
$_SERVER['REMOTE_ADDR']是 CDN 节点 IP,得从HTTP_X_FORWARDED_FOR提取真实 IP,但该 header 可伪造,务必配合 Nginx 的set_real_ip_from配置校验
别忽略共享内存 zone 的大小和淘汰机制
很多人设了 zone=mylimit:1m,结果线上跑两天就发现限流失效——不是配置没生效,是内存满了,旧 IP 条目被强制清掉,新攻击 IP 又挤进来了。
- 10MB zone ≈ 存 16 万个 IP 的计数状态,中小业务够用;高并发站点建议至少
zone=mylimit:50m - Nginx 每次新建条目时,最多删两条 60 秒未访问的旧记录;如果攻击 IP 持续刷,老记录根本不会被淘汰,新 IP 就进不来
- 可通过
nginx -T | grep limit_req_zone确认配置是否加载成功,再用curl -I http://your-site/看响应头是否有X-RateLimit-Limit(需额外加 echo 模块)
真正卡住 CC 攻击的,从来不是某一行 PHP 代码,而是 Nginx 配置里那几行不起眼的 limit_req_zone 和 limit_req;TP6.0 黑名单不是盾,是刀——得等敌人冲过第一道门,才轮到它出手。