一聚教程网:一个值得你收藏的教程网站

热门教程

服务器遭 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_reqlimit_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 块顶层,不能放在 serverlocation 里,否则 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_zonelimit_req;TP6.0 黑名单不是盾,是刀——得等敌人冲过第一道门,才轮到它出手。

热门栏目