在nginx中嵌入lua脚本是实现轻量、灵活、可热更新安全控制的最实用方式;推荐使用openresty,通过access_by_lua_file分离规则并热加载,支持sql注入拦截、ip限流、签名验证及redis协同。

直接在 Nginx 中嵌入 Lua 脚本,是实现轻量、灵活、可热更新的安全控制最实用的方式。不需要改核心配置、不依赖外部服务,规则写好 reload 就生效,特别适合中小团队或个人开发者对 API、后台、管理路径做精准防护。
基础环境准备:用 OpenResty 替代原生 Nginx
OpenResty 是集成了 LuaJIT 和常用模块(如 lua-nginx-module)的增强版 Nginx,开箱即用,省去手动编译模块的麻烦:
- 推荐使用 YUM 或 APT 安装官方 OpenResty 包,路径默认为
/usr/local/openresty - 验证是否就绪:
/usr/local/openresty/nginx/sbin/nginx -V 2>&1 | grep -o 'lua',有输出即表示 Lua 模块已加载 - 新建一个测试 location,确认 Lua 可执行:
location /test-lua { default_type text/plain; content_by_lua_block { ngx.say("Lua is working") } }
核心防护逻辑:从请求解析到拦截动作
Lua 安全规则本质是「获取请求上下文 → 匹配规则 → 执行动作」。常用变量和方法包括:
-
ngx.var.remote_addr:客户端真实 IP(注意代理场景需配合realip模块) -
ngx.var.request_uri和ngx.var.args:原始 URI 和查询参数字符串 -
ngx.req.get_uri_args()和ngx.req.get_post_args():结构化 GET/POST 参数 -
string.find()或ngx.re.match():做正则匹配(后者支持 PCRE,更安全) -
ngx.exit(ngx.HTTP_FORBIDDEN)或ngx.redirect("/deny.html", 302):立即中断或跳转
例如拦截含 select 或 union 的 SQL 注入特征:
if ngx.re.find(ngx.var.request_uri, [[select\s+from|union\s+select]], "io") then<br> ngx.log(ngx.ERR, "SQLi detected from ", ngx.var.remote_addr)<br> ngx.exit(403)<br>end
进阶能力:限流、签名验证与外部协同
单靠静态规则不够时,Lua 可调用 Nginx 生态能力扩展防护深度:
-
IP 级限流:用
ngx.shared.DICT在内存中计数,1 分钟超 50 次即拦截 -
请求头签名验证:读取
X-Sign,拼接 timestamp + body + secret 后用ngx.hmac_sha256校验一致性 -
Redis 协同:通过
resty.redis连接 Redis,实现跨节点共享黑名单或限流状态 -
日志记录:用
ngx.log(ngx.WARN, ...)输出结构化信息,便于对接 ELK 或 Prometheus
工程化建议:规则分离与热加载
避免把所有逻辑堆在配置文件里,推荐分层管理:
- 主配置中只保留
access_by_lua_file /path/to/waf/access.lua; -
access.lua负责流程调度,如加载规则、调用检测函数、统一响应 - 攻击特征单独存为
rules/sql_injection.lua、rules/xss.lua等,按需 require - 修改脚本后执行
nginx -s reload即可生效,无需重启进程











