核心是将校验逻辑前置到 access_by_lua_block 或 rewrite_by_lua_block 阶段,在请求发往后端前完成轻量、快速、可编程的判断,高效拦截非法参数以降低后端压力和攻击面。

Nginx 利用 Lua 脚本对请求参数做安全过滤与校验,核心是把校验逻辑前置到 access_by_lua_block 或 rewrite_by_lua_block 阶段,在请求发往后端前完成轻量、快速、可编程的判断。它不替代后端业务校验,但能高效拦截明显非法、可疑或格式错误的参数,降低后端压力和攻击面。
识别并提取关键参数
Lua 可直接读取结构化参数,比纯 Nginx 的 $arg_xxx 更灵活、更安全:
- GET 参数:用
ngx.req.get_uri_args()获取 table,支持重复键、自动解码 - POST 表单(application/x-www-form-urlencoded):用
ngx.req.get_post_args(),需确保client_max_body_size合理且未被禁用 - 注意:JSON 请求体需先由后端解析,Nginx 层不推荐直接解析 JSON 字符串(易出错、性能差),应改用请求头或 query 标识+签名验证
执行基础格式与存在性校验
重点检查“是否像合法请求”,而非“是否业务正确”:
- 强制必填参数存在:
if not args.token then ngx.exit(400) end - ID 类字段只接受正整数:
if not ngx.re.match(args.id, "^[1-9][0-9]*$") then ngx.exit(400) end - 时间戳限制为 10 或 13 位数字:
if not ngx.re.match(args.ts, "^([1-9][0-9]{9}|[1-9][0-9]{12})$") then ngx.exit(400) end - 拦截含控制字符、空格、尖括号、双引号等非法符号的参数值:
if ngx.re.find(args.q, "[ --<>'"\]") then ngx.exit(400) end
结合上下文做一致性判断
单独看参数不够,要放在请求场景中验证:
- POST 请求携带
action=delete,但Referer为空或非可信域名:查ngx.var.http_referer,匹配白名单后决定是否放行 - GET 请求中
data=参数超长(如 >2000 字符),疑似伪装 POST 或 base64 载荷:if args.data and #args.data > 2000 then ngx.exit(400) end - 敏感操作参数(如
?op=reset&user_id=123)出现在无认证头的请求中:检查ngx.req.get_headers()["Authorization"]是否存在且有效
拦截恶意模式与高风险特征
用正则主动识别攻击线索,避免依赖后端日志回溯:
- SQL 注入关键词:
ngx.re.find(ngx.var.request_uri, [[selects+from|unions+select|sleep(|benchmark(]], "io") - XSS 常见载荷:
ngx.re.find(args.callback, [[javascript:|data:text/html|onerror=|alert(]], "io") - 目录遍历尝试:
ngx.re.find(args.path, "../", "o") - 匹配成功后建议记录日志并返回 403:
ngx.log(ngx.ERR, "Blocked param pattern from ", ngx.var.remote_addr)→ngx.exit(403)
增强防护的进阶手段
单纯规则不够时,可联动外部能力提升水位:
- IP 级频控:用
ngx.shared.DICT计数,1 分钟内同一 IP 触发 3 次参数校验失败即临时封禁 - 参数签名验证:从
X-Sign头读签名,拼接timestamp + args_str + secret后用ngx.hmac_sha256校验,防止篡改 - 黑名单协同:通过
resty.redis查询 Redis 中的恶意参数哈希(如md5(arg_name..arg_value)),命中即拦截
不复杂但容易忽略


















