必须用access_by_lua_block在access阶段拦截,早于proxy_pass;若误用content_by_lua_block或后端拦截,请求已穿透网关,造成资源浪费且防护失效。

必须在请求进入业务逻辑前完成拦截,否则“穿透”已发生——Nginx + Redis 联动防穿透,核心不是查 Redis,而是用它做决策依据,且决策点不能晚于 access 阶段。
access_by_lua_block 是唯一可靠的拦截时机
把限流或封禁逻辑写在 content_by_lua_block 或后端服务里,等于让恶意请求已经穿过 Nginx 的关键防线。攻击者只要绕过网关、直连下游服务,或利用未鉴权的健康检查端点,整个防护就失效。
-
access_by_lua_block运行在 Nginx 的 access 阶段,早于 rewrite、proxy_pass 和日志记录,是 HTTP 请求生命周期中最早能做权限/流量决策的位置 - 错误做法:在
location /api/里用proxy_pass转发后再由 Spring Boot 的HandlerInterceptor拦——这时请求早已抵达应用层,Redis 查询、数据库连接、JWT 解析全已执行 - 正确链路:Nginx 接收请求 →
access_by_lua_block查 Redis 黑名单/计数器 → 若命中则ngx.exit(403)或ngx.redirect("/deny", 302),不进后端
Redis 键设计必须绑定真实身份维度
只按 $binary_remote_addr 封禁,对伪造 IP、NAT 环境、CDN 回源场景几乎无效;而只按固定 key(如 "global_rate")限流,则无法区分正常用户和恶意账号。
- 防单账号刷:用
"user_rate:" .. ngx.var.cookie_token或"user_rate:" .. ngx.ctx.userId(需前置解析 JWT 并校验签名) - 防 IP 扫描穿透:用
"ip_scan:" .. ngx.var.binary_remote_addr,配合INCR+EXPIRE原子计数 - 绝对避免硬编码 key:如
red:incr("blocked_ips")—— 这会导致所有 IP 共享一个计数器,失去隔离性 - 注意客户端行为:Lettuce 默认序列化
null为nil,Jedis 可能抛异常;存空值必须用"NULL"字符串,并显式判断if res == "NULL" then ...
布隆过滤器必须前置到 Nginx Lua 层,不能进业务才查
布隆过滤器(BloomFilter)不是缓存兜底手段,它是第一道“存在性筛子”。如果等请求走到 GET /user/9999999999 再去查布隆,恶意 key 早就打到 Redis 或 DB 了。
- 正确位置:在
access_by_lua_block中加载预热好的布隆结构(如用resty.bloomfilter或自建 bitset),对ngx.var.uri或提取出的 ID 参数做check() - 冷启动必须预热:上线前用全量合法
user_id或sku_id调用bloom:add(),否则首波请求误判率接近 100% - 误判率设为 1%(
error_rate=0.01)足够平衡内存与精度;设成 0.0001 会让初始化慢 3 倍以上,且对防穿透无实质提升 - 布隆只是“可能存在”,不能替代参数校验:仍需在网关层强转
Long userId、限制长度、校验正则,否则userId="admin'--"会直接绕过布隆
共享字典与连接池配置不当会放大延迟甚至雪崩
lua_shared_dict 和 Redis 连接池不是可选项,而是性能生死线。没配连接池时,每请求新建 Redis 连接,1000 QPS 就可能耗尽 socket 资源;共享字典大小不足,会导致频繁淘汰,使限流/封禁状态丢失。
-
lua_shared_dict ip_blacklist 10m至少保留 10MB,用于缓存近期高频 IP 的封禁状态(减少 Redis 往返) - 连接池参数示例:
local ok, err = red:set_keepalive(60000, 100),空闲连接最长保持 60 秒,最大池容量 100 - Redis 超时必须设严:
red:set_timeouts(100, 100, 100)(connect/read/write 各 100ms),避免单次卡顿拖垮整条请求链 - 务必加降级开关:当
red:connect()失败或red:exists()报错时,不能默认放行(形同裸奔),应结合本地内存缓存或返回 503
真正难的不是写几行 Lua 脚本,而是确保每个环节都卡在“请求刚进来、什么都还没干”的那个精确时间点——从 Nginx 阶段选择、Redis key 结构、布隆预热方式,到连接池回收策略,漏掉任何一环,恶意流量都会找到缝隙钻进去。











