Nginx + Lua 是生产环境中拦截自动化暴力注入最轻量高效的前置防线,需在 access 阶段通过 access_by_lua_file 精准识别高频参数爆破、可疑关键字、异常编码及 UA/Referer 特征,并结合频率限制、语义解码检测与白名单策略分层防御。

在生产环境中,Nginx + Lua 是拦截自动化暴力注入(如参数爆破、SQL 注入、NoSQL 注入、恶意 token 枚举等)最轻量、最高效的一道前置防线。关键不在于“写一个万能脚本”,而在于精准识别攻击特征、快速响应、不干扰正常业务。
识别高危 URL 参数行为
暴力注入通常表现为高频、模式化、非人工可读的参数请求,例如:
-
固定路径 + 变化参数值:如
/api/login?username=admin&password=123→ 短时间内大量不同 password 值 -
含可疑关键字的参数内容:如
args.password中出现' OR '1'='1、admin$ne(NoSQL)、sleep(5)、union select - 超长/异常编码参数:如 base64 编码后解码含 SQL 片段、URL 编码嵌套多层、%00 截断等
-
无 Referer 或 User-Agent 异常:空、极简(如
curl/7.68.0)、或伪造为已知扫描器(sqlmap,nuclei)
用 access_by_lua_file 实现低开销拦截
推荐在 access 阶段拦截,避免进入后端再拒绝,节省资源。配置示例:
location /api/ {
lua_need_request_body on;
access_by_lua_file /etc/nginx/lua/block_brute_params.lua;
proxy_pass http://backend;
}
对应 Lua 脚本需聚焦三件事:
- 提取并解码关键参数(如
username、password、token),注意处理application/x-www-form-urlencoded和application/json两种常见格式 - 对参数值做轻量正则匹配(如
string.find(val, "["';\-\+\|\&\^\`\$\(\)\[\]\{\}]+")),不建议全文本解析 JSON 再校验——性能代价高 - 命中规则时直接返回 403,并记录 IP 到共享字典用于短时封禁(
lua_shared_dict block_cache 10m;)
防御策略要分层,不能只靠关键词
单靠黑名单关键词易绕过,应组合使用:
-
频率限制:同一 IP 在 60 秒内对含
password参数的请求 ≥ 10 次,自动触发临时封禁(用ngx.shared.block_cache计数) -
语义简化检测:对参数值做 HTML/XML/URL 解码后,再检查是否含 SQL 关键字;对 JSON 参数,可简单匹配
{.*["']\$.*["']:类似 NoSQL 操作符结构 -
白名单兜底:对已知安全参数(如
page=1&size=20),可跳过校验;对敏感操作接口(如/login,/reset_password),强制启用全量校验 -
拒绝未声明 Content-Type 的 POST:
if ngx.req.get_headers()["Content-Type"] == nil then ngx.exit(400) end
上线前必须验证的细节
真实环境容易忽略但影响巨大:
- 确保
lua_package_path正确指向脚本目录,路径末尾加;;允许子目录查找 -
lua_shared_dict大小按并发量预估(每 IP 约 256 字节),避免缓存击穿 - 所有字符串匹配前先判空、判类型,防止
nil导致 500 错误(if not val or type(val) ~= "string" then return end) - 日志中记录被拦截的原始 URI 和参数名(不记敏感值),便于后续分析攻击模式
- 首次上线建议先
ngx.log(ngx.WARN, ...)打印不拦截,确认逻辑无误后再启用ngx.exit(403)


















