Nginx+Lua实现SQL注入防护:轻量级WAF配置与实战指南
1. 项目概述
最近在梳理线上Web服务的防护策略,发现很多针对数据库的直接攻击,SQL注入依然是绕不开的“老朋友”。虽然应用层有ORM框架和参数化查询,但在网关层面加一道防线,总归是多一份安心。我选择了在Nginx这一层,用Lua脚本来实现一个轻量级的SQL注入防火墙。这个方案的好处是性能损耗极低,部署灵活,不侵入业务代码,能拦截掉大部分自动化扫描和初级攻击。如果你也在用Nginx做反向代理或Web服务器,想在不改动后端代码的情况下增强安全性,那这套配置思路值得你花十分钟了解一下。
简单说,这个配置的核心就是利用Nginx的ngx_http_lua_module模块,在请求到达后端PHP、Java或Python应用之前,对请求的URL参数、POST数据、Cookie甚至User-Agent进行实时检测,一旦发现疑似SQL注入的特征,就直接在Nginx层面返回403禁止访问,攻击流量根本到不了你的应用服务器。下面,我就把从环境准备、规则配置到调试优化的完整过程拆开揉碎了讲给你听。
2. 核心思路与架构设计
2.1 为什么选择Nginx + Lua?
首先得想明白,防SQL注入的手段很多,为什么偏偏选这个组合?从我的经验看,主要是三个原因:性能、灵活性和无侵入性。
性能:Nginx本身以高性能著称,而Lua脚本在Nginx中运行是通过LuaJIT即时编译的,速度非常快。将过滤逻辑放在Nginx这一层,相比在每一个后端应用里都写一遍过滤逻辑,或者引入一个沉重的Web应用防火墙(WAF)硬件,其资源消耗几乎可以忽略不计。对于高并发场景,这一点至关重要。
灵活性:Lua语法简洁,规则可以写得非常灵活。你可以轻松地自定义检测规则,比如针对自家业务特有的API参数进行特殊处理,或者快速响应新型的攻击模式。今天看到一个新的SQL注入绕过技巧,明天就能把对应的正则规则更新上去,响应速度比等待商业WAF厂商更新规则库要快得多。
无侵入性:这是我最看重的一点。你不需要修改任何后端Java、Go或PHP的代码。所有的防护逻辑都前置在Nginx配置里。对于维护一个庞大且历史悠久的系统来说,这种“手术刀”式的方案风险最低。即使防护规则出了点小问题,比如误拦截了正常请求,也只需要回滚Nginx配置,不会影响核心业务逻辑。
2.2 整体防护流程设计
整个防火墙的工作流程,可以想象成一道安检门。当一个HTTP请求到达Nginx时,会依次经过以下几个检查点:
- 白名单检查:首先核对请求的IP、URL是否在信任的白名单内。如果是,直接放行,后续所有检查跳过。这通常用于放行监控系统、内部API调用或已知安全的爬虫。
- 黑名单检查:检查请求IP是否在已知的攻击者黑名单中。如果是,直接拒绝。这个名单可以动态更新,比如将短时间内触发多次拦截的IP加入其中。
- SQL注入规则检测:这是核心环节。对请求的多个部分进行扫描:
$args(GET查询参数):如?id=1中的1。$request_uri(原始请求URI):包含参数的完整路径。$request_body(POST请求体):如表单提交的JSON或x-www-form-urlencoded数据。$http_cookie(Cookie内容)。$http_user_agent(浏览器标识)。 将这些内容与预定义的SQL注入特征正则表达式进行匹配。
- 处置动作:一旦在任何环节匹配到攻击特征,立即执行预设动作。通常是直接返回
403 Forbidden,并记录日志。更高级的可以返回一个伪造的错误页面,或者将请求重定向到一个“蜜罐”页面来拖延攻击者。
整个流程在access_by_lua_block阶段执行,这是Nginx处理请求的早期阶段,能在请求进入后端之前就完成拦截,最大化地节省后端资源。
2.3 工具与组件选型
这里我们不从零造轮子,而是基于一个成熟的开源项目进行定制。我选择的是loveshell/ngx_lua_waf。这个项目在Github上Star数不少,社区活跃,规则也比较全面。它本身提供了防SQL注入、XSS、文件包含等多种Web攻击的规则,我们主要取其SQL注入防护部分,并根据自身业务进行裁剪和强化。
注意:直接使用开源WAF规则可能存在误报。商业WAF的规则库经过大量线上流量训练和人工修正,误报率控制得很好。而开源规则更偏向于“宁可错杀,不可放过”,我们需要花时间调整,避免影响正常用户。
你需要确保的Nginx环境支持Lua模块。通常,通过包管理器安装的nginx-full或自行编译时加入--with-http_lua_module参数都可以。我们接下来的操作基于Ubuntu/Debian系统,CentOS/RHEL系列在包名上略有不同,但思路完全一致。
3. 环境准备与核心配置详解
3.1 Nginx与Lua模块安装
如果你的系统还没有Nginx,或者现有的Nginx不支持Lua,我们需要先搞定环境。
对于Ubuntu/Debian:
# 更新软件包列表 sudo apt-get update # 安装包含Lua模块的Nginx版本。通常`nginx-extras`包会包含更多模块。 sudo apt-get install nginx-extras lua5.3 liblua5.3-dev # 验证Nginx安装及版本,确认包含`http_lua_module` sudo nginx -V 2>&1 | grep lua如果输出中包含--with-http_lua_module,说明安装成功。
对于CentOS/RHEL:EPEL源中的Nginx可能默认不包含Lua模块。更可靠的方式是通过OpenResty的Yum源安装OpenResty,它包含了增强的Nginx和LuaJIT。或者,如果你必须使用标准Nginx,就需要手动编译。
# 添加OpenResty仓库(推荐,一站式解决) sudo yum install yum-utils sudo yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo sudo yum install openresty # OpenResty的Nginx二进制文件通常是`openresty`,配置文件路径也可能不同(如/usr/local/openresty/nginx/conf/),请注意调整后续命令。安装完成后,先启动Nginx并设置开机自启:
sudo systemctl start nginx sudo systemctl enable nginx访问你的服务器IP,应该能看到Nginx的欢迎页面。
3.2 部署ngx_lua_waf防火墙规则
接下来,我们获取并部署核心的防火墙规则。
# 1. 切换到合适的目录,比如Nginx配置目录下 cd /etc/nginx # 2. 克隆WAF项目 sudo git clone https://github.com/loveshell/ngx_lua_waf.git waf # 3. 进入目录查看结构 cd /etc/nginx/waf ls -la你会看到类似以下结构:
config.lua # 主配置文件 init.lua # 初始化脚本 wafconf/ # 规则目录 ├── args # GET参数规则 ├── post # POST数据规则 ├── url # URL路径规则 ├── user-agent # User-Agent规则 ├── cookie # Cookie规则 └── whiteurl # URL白名单3.3 核心配置文件解析与调优
现在我们来仔细看看config.lua,这是防火墙的大脑。
-- 配置文件通常开头是这样的 RulePath = "/etc/nginx/waf/wafconf/" -- 规则存放路径 attacklog = "on" -- 是否开启攻击日志 logdir = "/var/log/nginx/hack/" -- 攻击日志存放目录 UrlDeny="on" -- 是否拦截URL攻击 Redirect="on" -- 是否重定向攻击请求 CookieMatch="on" -- 是否检查Cookie postMatch="on" -- 是否检查POST数据 whiteModule="on" -- 是否开启URL白名单 black_fileExt={"php","jsp"} -- 禁止访问的文件扩展名 ipWhitelist={"127.0.0.1"} -- IP白名单 ipBlocklist={"1.0.0.1"} -- IP黑名单 CCDeny="off" -- 是否开启CC攻击防护 CCrate="100/60" -- CC防护阈值,60秒内100次请求你需要重点调整的几个地方:
RulePath:确认这个路径和你实际放置wafconf目录的路径一致。logdir:确保这个目录存在且Nginx进程用户(通常是www-data或nginx)有写入权限。sudo mkdir -p /var/log/nginx/hack/ sudo chown -R www-data:www-data /var/log/nginx/hack/ # 根据你的Nginx用户调整black_fileExt:根据你的业务调整。如果你的网站就是提供.php文件访问,那肯定不能加php。这里通常用于防止访问某些敏感备份文件,如.bak,.sql,.tar.gz等。我一般会加上:black_fileExt={"php", "jsp", "asp", "aspx", "bak", "sql", "tar.gz", "zip", "rar", "old", "swp"}注意:这里对
.php等的拦截,指的是直接通过URL访问这些源文件。如果你的网站是PHP动态网站,用户访问的是/index.php这种由Nginx交给PHP-FPM处理的路径,不会触发此拦截。此规则主要用于防止扫描器探测/index.php.bak这类备份文件。ipWhitelist:把你的管理服务器IP、监控系统IP加进去,避免自己的操作被拦截。CCDeny和CCrate:CC攻击防护对于防刷接口、防爬虫很有用,但初期建议先设为"off"。等SQL注入防护稳定后,再根据业务压力情况开启并调整阈值。“100/60”表示60秒内同一IP访问超过100次则触发防护。
3.4 将WAF集成到Nginx主配置
这是最关键的一步,让Nginx在处理每个请求时都调用我们的Lua防火墙。
打开你的Nginx站点配置文件,通常位于/etc/nginx/sites-available/default或/etc/nginx/conf.d/下的某个文件。在server块中,添加以下配置:
server { listen 80; server_name your_domain.com; # 1. 设置Lua包路径和共享内存(用于CC防护等) lua_package_path "/etc/nginx/waf/?.lua;;"; lua_shared_dict limit 10m; # 定义10M的共享内存区域,名为limit # 2. 初始化WAF。这里加载config.lua和init.lua。 init_by_lua_file /etc/nginx/waf/init.lua; # 3. 在访问阶段执行WAF检测 access_by_lua_file /etc/nginx/waf/waf.lua; # 你原有的location配置,比如根目录或反向代理 location / { root /var/www/html; index index.html index.htm; # 如果你的后端是PHP,可能需要这样的配置 # try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; } # 4. 可选:为拦截请求自定义错误页面 error_page 403 /403.html; location = /403.html { root /var/www/html; internal; # 标记为内部位置,只能由Nginx内部重定向访问 } }配置解析与注意事项:
lua_package_path:告诉Nginx去哪里找我们写的Lua模块。;;表示在原有路径后追加。init_by_lua_file:在NginxMaster进程启动时执行一次,用于加载全局配置和规则。这里加载init.lua,它会读取config.lua和wafconf/下的规则文件到内存中。规则修改后,必须重载或重启Nginx才能生效。access_by_lua_file:在Nginx处理请求的access阶段对每一个请求执行waf.lua。这是执行检测和拦截逻辑的地方。lua_shared_dict:定义了一块所有NginxWorker进程之间共享的内存。这对于实现IP级别的频率限制(CC防护)是必须的,因为每个Worker进程独立,需要共享计数信息。error_page 403:当WAF拦截请求时,Nginx会返回403状态码。这里配置了一个自定义的403页面,提升用户体验(或者迷惑攻击者)。记得创建/var/www/html/403.html这个文件。
配置完成后,一定要测试配置文件语法是否正确:
sudo nginx -t如果显示“syntax is ok”和“test is successful”,就可以安全地重载配置了:
sudo systemctl reload nginx重载(reload)是平滑重启,不会断开现有连接,是线上服务更新的推荐方式。
4. SQL注入规则深度解析与定制
开源WAF的规则是基础,但直接使用往往误报率不低。我们必须理解其原理,并学会调整。
4.1 规则文件结构与语法
打开一个规则文件,例如/etc/nginx/waf/wafconf/args(用于检测GET参数):
(?:updatexml|extractvalue|exp|geometrycollection|polygon|multipoint|linestring|multilinestring|multipolygon)\s*\( select.+(from|limit) (?:(union(.*?)select)) having|sleep|benchmark\s*\( \b(?:d(?:eclare|rop)|i(?:nsert|nto)|create|exec)\b [\s\S]*?(?:--|#|\/\*)每一行都是一个正则表达式。当请求参数中的字符串匹配上任何一行时,就会被判定为攻击。
常见规则模式解读:
- 关键字检测:如
select.+from、union.*?select、insert into、drop table等。这是最基础的检测。 - 函数与操作检测:如
updatexml()、extractvalue()是MySQL的报错注入函数;sleep()、benchmark()是时间盲注函数;exp()是溢出报错注入函数。 - 注释符检测:如
--、#、/* */,SQL注入中常用注释符来截断后续SQL语句。 - 编码与混淆绕过检测:一些高级规则会包含十六进制、URL编码、双重编码的变种。例如
SELECT可能被写为SEL%45CT(URL编码)或0x53454c454354(十六进制)。开源规则在这方面通常较弱。
4.2 如何降低误报:调整与白名单
误报是自建WAF最大的痛点。比如,一个新闻网站有一篇标题为《Sleep函数在编程中的使用》的文章,URL可能是/article?id=123,文章内容里包含“sleep”这个词。如果规则简单地匹配sleep,这个正常请求就会被拦截。
调整策略:
- 精确化正则表达式:避免过于宽泛的匹配。例如,将
sleep改为sleep\s*\(,这样只匹配sleep(函数调用,而不是单词本身。 - 使用白名单:
ngx_lua_waf提供了whiteurl文件(URL白名单)和config.lua中的ipWhitelist(IP白名单)。- URL白名单:在
wafconf/whiteurl文件中,每行写一个正则表达式,匹配的URL将跳过所有WAF检查。例如,如果你的搜索接口/api/search允许用户输入复杂查询,容易误报,可以添加:^/api/search$ - IP白名单:在
config.lua的ipWhitelist表中添加IP。这对于后端服务器间内部调用、运维管理平台非常有用。
- URL白名单:在
- 注释掉过于激进的规则:仔细阅读
args、post等文件,对于你确认会引发大量误报且防护价值不高的规则,可以在行首加--(Lua注释符)暂时禁用。务必在测试环境充分验证后再操作线上。
4.3 增强防护:添加自定义规则
开源规则可能覆盖不了所有情况,你需要根据业务和最新的攻击趋势添加规则。
案例:防御布尔盲注的LIKE语句一些布尔盲注会使用LIKE子句进行逐字符猜测。我们可以添加规则:
\blike\s+['\"%]这个规则匹配like ‘%或like “%这种模式。
添加步骤:
- 编辑对应的规则文件,如
/etc/nginx/waf/wafconf/args。 - 在文件末尾新增一行,写上你的正则表达式。
- 保存文件。
- 重载Nginx配置:
sudo systemctl reload nginx。因为规则是在init_by_lua_file阶段加载到内存的,修改规则文件后必须重载。
重要心得:添加新规则后,一定要用正常的业务流量进行测试。可以先将Nginx日志级别调为
info或debug,观察一段时间,确保没有误拦截正常请求。也可以编写简单的测试脚本,模拟用户行为进行自动化测试。
5. 实战测试与效果验证
配置好了不测试,等于没做。我们需要模拟攻击,验证防火墙是否生效,同时也要验证正常业务是否畅通。
5.1 搭建测试环境
为了安全,强烈建议在一个独立的测试服务器或虚拟机上操作。安装一个简单的带数据库的Web应用用于测试,比如DVWA(Damn Vulnerable Web Application)或者一个自己写的有SQL注入漏洞的PHP页面。
例如,创建一个简单的测试文件/var/www/html/test.php:
<?php // 警告:此代码存在严重SQL注入漏洞,仅用于测试,切勿用于生产环境! $id = $_GET['id'] ?? '1'; $conn = new mysqli('localhost', 'test_user', 'test_pass', 'test_db'); if ($conn->connect_error) die("Connection failed: " . $conn->connect_error); $sql = "SELECT * FROM users WHERE id = " . $id; // 这里没有过滤,存在注入! $result = $conn->query($sql); if ($result->num_rows > 0) { while($row = $result->fetch_assoc()) { echo "id: " . $row["id"]. " - Name: " . $row["name"]; } } else { echo "0 results"; } $conn->close(); ?>5.2 模拟SQL注入攻击
使用浏览器或curl命令进行测试:
- 基础注入测试:尝试访问
http://your_server_ip/test.php?id=1%20or%201=1--%20-- 这会被规则
\bor\b或--匹配到,应该返回403。
- 这会被规则
- 联合查询注入测试:
http://your_server_ip/test.php?id=1%20union%20select%201,2,3--%20-- 这会被
union.*?select规则匹配。
- 这会被
- 报错注入测试:
http://your_server_ip/test.php?id=1%20and%20updatexml(1,concat(0x7e,(select%20user())),1)--%20-- 这会被
updatexml\s*\(规则匹配。
- 这会被
- 时间盲注测试:
http://your_server_ip/test.php?id=1%20and%20sleep(5)--%20-- 这会被
sleep\s*\(规则匹配。
- 这会被
观察结果:
- 如果配置正确,上述请求都应该收到
403 Forbidden响应,而不是执行SQL语句或返回数据库错误信息。 - 同时,检查攻击日志目录
/var/log/nginx/hack/,应该能看到以日期命名的日志文件,里面记录了拦截的详细信息,包括攻击IP、时间、拦截的URL、匹配的规则等。这是事后审计和攻击分析的重要依据。
5.3 验证正常业务请求
这是更关键的一步,确保你的防护不会“误伤友军”。
- 测试正常请求:访问
http://your_server_ip/test.php?id=1。这应该能正常返回数据库中的结果(如果数据库里有id=1的用户)。 - 测试边界情况:
- 参数包含正常英文单词,如
/search?q=sleep(搜索“sleep”)。 - 参数包含数字和特殊符号,如
/api/data?range=1-100。 - POST请求提交JSON数据,如
{"username": "admin'--"},注意这里的单引号和注释符可能会被误判。你需要根据业务判断是否将其加入白名单或调整规则。
- 参数包含正常英文单词,如
测试方法:
- 手动测试:用浏览器和开发者工具,逐个测试关键业务接口。
- 自动化测试:使用Postman、JMeter或编写Python脚本,模拟用户会话,遍历主要功能点。
- 监控日志:在测试期间,密切观察Nginx的错误日志(
/var/log/nginx/error.log)和WAF攻击日志。如果发现大量403错误来自真实用户IP,说明存在误报,需要立即排查。
6. 高级调优与运维管理
配置上线只是开始,持续的运维和调优才能让这套防火墙真正发挥作用。
6.1 性能监控与影响评估
虽然Lua WAF很轻量,但仍需关注其性能影响。
- 监控Nginx指标:
- 请求吞吐量 (RPS):对比开启WAF前后的变化。
- 平均响应时间:关注是否因规则匹配而增加。
- Nginx Worker进程CPU和内存使用率:使用
top或htop命令,查看nginxworker进程的资源消耗。
- 使用
ngx.log进行调试:在waf.lua的关键逻辑处添加日志,可以了解匹配过程和耗时。但生产环境要谨慎,避免日志泛滥。ngx.log(ngx.NOTICE, "Checking args: ", ngx.var.args) - 压力测试:使用
wrk或ab工具对关键接口进行压测,对比开启/关闭WAF时的性能数据。wrk -t12 -c400 -d30s http://your_server_ip/test_normal_page
6.2 规则动态更新与版本管理
规则需要与时俱进。你需要建立一个更新流程。
- 订阅安全情报:关注OWASP、CNVD、安全厂商博客,了解新型SQL注入手法。
- 测试新规则:在测试环境验证新规则的有效性和误报率。
- 版本化管理配置:将
/etc/nginx/waf/目录纳入Git版本控制。每次修改规则或配置都进行提交,方便回滚和审计。 - 自动化更新(谨慎):可以编写脚本,定期从可信源拉取规则更新,并在测试后自动应用到生产环境。但务必设置人工审核环节,自动化更新规则风险极高。
6.3 与其他安全措施联动
Nginx Lua WAF是纵深防御体系中的一层,不应是唯一的一层。
- 与网络防火墙联动:当WAF在短时间内拦截同一个IP多次后,可以通过Lua脚本调用系统命令(如
iptables)或API,将该IP加入系统层面的防火墙黑名单,实现更长时间的封禁。注意:在Nginx Worker中执行系统命令有性能和安全风险,需谨慎设计,通常建议通过日志分析工具(如Fluentd+Elasticsearch)离线分析后,再通过脚本批量操作iptables。 - 日志分析与告警:将
/var/log/nginx/hack/的日志接入ELK(Elasticsearch, Logstash, Kibana)或Splunk等日志分析平台。可以设置告警规则,例如:同一IP在1分钟内触发超过10次SQL注入拦截,则发送邮件或短信告警。 - 作为反向代理时的配置:如果你的Nginx主要用作反向代理(
proxy_pass到后端应用服务器),WAF配置的位置至关重要。必须确保access_by_lua_file指令在location块中,且在proxy_pass指令之前执行。location /yourapp/ { access_by_lua_file /etc/nginx/waf/waf.lua; # 先执行WAF检查 proxy_pass http://backend_server; # 通过检查后再转发 proxy_set_header Host $host; ... }
7. 常见问题排查与解决实录
在实际部署和运维中,我踩过不少坑。这里把典型问题和解决方法列出来,希望能帮你节省时间。
7.1 WAF完全不生效,攻击请求畅通无阻
- 症状:模拟的SQL注入攻击可以正常执行,返回数据库结果或错误,Nginx没有返回403。
- 排查步骤:
- 检查Nginx错误日志:
sudo tail -f /var/log/nginx/error.log。在测试攻击时,观察是否有Lua相关的错误信息。最常见的是Lua模块未加载或脚本语法错误。 - 验证Lua模块:确保
nginx -V输出中包含--with-http_lua_module。如果不包含,你需要重新编译Nginx或安装nginx-extras包。 - 检查配置文件语法:运行
sudo nginx -t,确保没有语法错误。特别注意lua_package_path和文件路径是否正确。 - 检查WAF日志目录权限:确保
/var/log/nginx/hack/目录存在,且Nginx进程用户(如www-data)对其有写权限。权限问题会导致WAF初始化失败而静默退出。 - 在WAF脚本中加日志:临时在
waf.lua文件开头添加ngx.log(ngx.ERR, "WAF script loaded and executing"),重载Nginx后访问页面,看错误日志中是否有这条记录。如果没有,说明脚本根本没被执行,检查access_by_lua_file指令的位置和路径。
- 检查Nginx错误日志:
7.2 误报太多,正常请求被拦截
- 症状:用户反馈无法登录、搜索失败、页面显示403。
- 排查步骤:
- 定位被拦截的请求:查看
/var/log/nginx/hack/下的日志,找到被拦截的正常请求记录。日志里会写明匹配到的规则内容和拦截部分(args/post/url等)。 - 分析匹配规则:根据日志中的规则内容,去对应的规则文件(如
args)里找到该行正则表达式。 - 理解误报原因:分析正常请求的参数为何会匹配攻击规则。例如,用户昵称叫“Union”,在查询时参数
?name=Union可能触发union规则。 - 解决方案:
- 优化规则:使正则更精确。例如将
union改为union\s+select。 - 添加白名单:如果这个误报的接口是固定的,将其URL添加到
wafconf/whiteurl白名单文件中。 - 临时禁用规则:如果某条规则过于激进且误报频繁,可以在行首加
--注释掉,但必须评估安全风险。
- 优化规则:使正则更精确。例如将
- 测试验证:修改后,重载Nginx,并复现之前被误报的用户操作,确认问题解决。
- 定位被拦截的请求:查看
7.3 性能明显下降,服务器负载升高
- 症状:开启WAF后,网站响应变慢,服务器CPU使用率上升。
- 排查步骤:
- 检查规则复杂度:过于复杂的正则表达式(尤其是包含
[\s\S]*?这种贪婪匹配且范围广的)会严重消耗CPU。使用工具测试正则表达式的效率。 - 检查规则数量:
wafconf目录下每个文件的行数是否过多?成千上万条规则逐行匹配,开销必然大。定期清理过期、无效或重复的规则。 - 使用
ngx.location.capture进行子请求?:有些WAF实现会为了获取POST数据而发起子请求,这是非常耗性能的操作。确保你的WAF脚本是直接读取ngx.var.request_body(需要显式配置lua_need_request_body on;)。 - 进行性能剖析:可以使用OpenResty的
ngx-lua-profiler工具,或者简单地在代码前后记录时间戳,找出最耗时的检测函数或规则。 - 优化策略:
- 分阶段检测:先进行快速、简单的关键字匹配(如
union、select),如果匹配上,再进行更复杂的正则匹配。 - 设置检测开关:在
config.lua中为不同的检测项(如postMatch、CookieMatch)提供开关,对不必要检查的请求类型可以关闭。 - 升级硬件:如果经过优化后性能仍不满足要求,考虑升级服务器CPU。
- 分阶段检测:先进行快速、简单的关键字匹配(如
- 检查规则复杂度:过于复杂的正则表达式(尤其是包含
7.4 攻击日志没有记录
- 症状:请求被拦截返回403,但
/var/log/nginx/hack/目录下没有日志文件。 - 排查步骤:
- 检查
config.lua设置:确认attacklog = "on",并且logdir路径正确。 - 检查目录权限:这是最常见的原因。确保日志目录存在,且Nginx进程用户有写入权限。可以手动切换用户测试:
sudo -u www-data touch /var/log/nginx/hack/test.log。 - 检查磁盘空间:使用
df -h命令,确保磁盘未满。 - 查看Nginx错误日志:在写入攻击日志时发生错误(如权限不足)会在Nginx错误日志中体现。
- 检查
7.5 重载Nginx后配置不生效
- 症状:修改了
config.lua或wafconf/下的规则文件后,执行sudo systemctl reload nginx,但新规则似乎没起作用。 - 原因与解决:规则是在Nginx启动时由
init_by_lua_file加载到内存中的。reload操作会重新加载配置文件,但不会重新执行init_by_lua_file(Master进程初始化只发生一次)。修改规则后,需要重启Nginx服务:sudo systemctl restart nginx。注意:重启会断开现有连接,对线上服务有影响。建议在低峰期操作,或者采用双机热备轮流重启的方式。也可以考虑将规则存储在Redis等外部缓存中,实现动态加载,但这会显著增加架构复杂度。
这套Nginx Lua防火墙的配置,从原理到实践,从部署到调优,基本就这些内容了。它不是一个一劳永逸的银弹,而是一个需要你持续维护和调整的“活”系统。初期花费时间调试规则、处理误报是不可避免的,但一旦稳定下来,它就能为你后端的应用服务器提供一个安静、可靠的防护屏障。我的体会是,安全是一个过程,这套自建WAF的方案,最大的价值在于让你更贴近流量,更了解攻击者的手法,从而在整体安全架构上做出更明智的决策。
