nginx + lua 防 cc 攻击的核心是在 access 阶段实时统计单个 ip 在指定时间窗口内的请求次数并动态拦截超限访问;需基于 openresty 和 redis 实现原子计数、路径级控制及降级策略。

用 Nginx + Lua 脚本防 CC 攻击,核心是**在 access 阶段实时统计单个 IP 在指定时间窗口内的请求次数,并动态拦截超限访问**。原生 Nginx 的 limit_req 虽稳定,但粒度固定、无法按业务逻辑灵活判断(比如只限 /login 接口、跳过白名单、结合 Redis 共享状态)。Lua 方案能精准控制,适合高并发场景下的细粒度防护。
一、基础环境准备:OpenResty + Redis
必须使用 OpenResty(非原生 Nginx),它已集成 lua-nginx-module 和 resty.redis 库,无需手动编译模块:
- 安装 OpenResty(推荐官方源一键安装,避免版本兼容问题)
- 安装并启动 Redis(用于跨 worker 进程共享计数,保证准确性)
- 确认 Nginx 配置中已启用 Lua 相关指令,例如:
lua_package_path "/usr/local/openresty/lualib/?.lua;;";init_by_lua_block { require "resty.core" }
二、Lua 脚本实现单位时间频次统计与拦截
以「10 秒内最多允许 20 次访问」为例,脚本放在 access_by_lua_file 中执行:
- 用
ngx.var.remote_addr获取客户端真实 IP(若经代理,需配合real_ip模块修正) - 构造 Redis key,如
"cc:ip:" .. ngx.var.remote_addr - 调用
redis:get(key)获取当前计数;若为空,用redis:set(key, 1)并设expire(10) - 若已有值,用
redis:incr(key)增加计数,再判断是否 > 20;超限则ngx.exit(403) - 务必调用
set_keepalive归还连接,避免连接耗尽
注意:脚本需处理 Redis 连接失败、超时等异常,失败时建议放行(fail-open),避免雪崩。
三、按路径/条件精细化控制
CC 攻击常集中于登录、搜索、下单等接口,不应对全站统一限流:
- 在 location 块中嵌入脚本,仅对目标路径生效,例如:
location /login { access_by_lua_file /path/to/cc_check.lua; } - 利用
ngx.var.request_uri或ngx.var.host做多维判断,比如只统计含?page=的 URL - 可配合
map指令预定义白名单 IP 或内部 UA,脚本中直接跳过统计
四、增强可靠性:加锁与降级策略
高并发下多个 worker 可能同时读写同一 key,Redis 的 INCR 本身是原子操作,但首次 SET+EXPIRE 非原子——需规避竞态:
- 改用 Redis 的
EVAL执行 Lua 脚本(服务端原子执行),或使用SET key value EX 10 NX确保 set-if-not-exists - 配置本地 fallback 计数器(如 Lua shared dict),当 Redis 不可用时临时启用,降低精度保可用
- 记录拦截日志:
ngx.log(ngx.WARN, "CC blocked: ", ngx.var.remote_addr),便于后续分析攻击特征











