网站上线之后,最先撞上来的往往不是业务问题,而是攻击:SQL 注入、XSS 跨站脚本、恶意爬虫、CC 高频请求。很多站长以为装了宝塔面板、开了系统防火墙就万事大吉,实际上这些默认防护根本拦不住应用层攻击。本文以 Nginx 环境为例,手把手教你用 ModSecurity 搭配 OWASP 核心规则集(CRS)自建一套可落地的 WAF 规则,从规则安装、站点接入到误报调优一次讲透。
一、为什么自建 WAF 推荐 ModSecurity + OWASP CRS
ModSecurity 是目前最成熟的开源 Web 应用防火墙引擎,支持 Nginx、Apache 等多种 Web 服务器,本身只是一套检测引擎,真正起作用的是它加载的规则集。OWASP CRS(Core Rule Set)是全球应用最广的免费规则集,内置了 SQL 注入、XSS、命令注入、路径遍历、恶意文件上传、协议攻击等几百条规则,覆盖 OWASP Top 10 中的绝大多数攻击类型。两者组合,等于给 Nginx 套上了一层应用层”安检门”。
自建 WAF 适合对成本敏感、数据不出站的场景;如果服务器带宽有限、或者需要抵御大流量 DDoS 与 CC 攻击,建议把防护前置到 CDN/WAF 云防护节点,让恶意流量在到达源站之前就被清洗掉(后文总结会具体说)。
二、环境准备:安装 ModSecurity 并接入 Nginx
推荐使用 Nginx 官方源或宝塔面板的编译方式,将 ModSecurity 编译为动态模块,便于后续升级。以下以 Ubuntu 22.04 + 源码编译为例:
# 1. 安装依赖
sudo apt update
sudo apt install -y build-essential libpcre3-dev libxml2-dev libcurl4-openssl-dev libyajl-dev liblua5.1-dev libgeoip-dev libpcre2-dev
# 2. 获取 Nginx 源码(版本以你线上版本为准)
wget https://nginx.org/download/nginx-1.24.0.tar.gz
tar xzf nginx-1.24.0.tar.gz
# 3. 克隆 ModSecurity 并编译动态模块
git clone --depth 1 https://github.com/SpiderLabs/ModSecurity
cd ModSecurity
git submodule init && git submodule update
./build.sh
./configure --with-yajl --with-lua
make -j$(nproc)
# 4. 编译 Nginx 动态模块
cd ../nginx-1.24.0
./configure --with-compat --add-dynamic-module=../ModSecurity/nginx/modsecurity
make modules
sudo cp objs/ngx_http_modsecurity_module.so /usr/lib/nginx/modules/
在 nginx.conf 顶部加载模块,并准备 ModSecurity 主配置:
# nginx.conf 顶部
load_module /usr/lib/nginx/modules/ngx_http_modsecurity_module.so;
# ModSecurity 主配置 modsecurity.conf(关键项)
SecRuleEngine On # On=开启拦截 / DetectionOnly=仅记录
SecRequestBodyAccess On # 开启请求体检测(SQL注入/XSS 关键)
SecRequestBodyLimit 13107200 # 请求体上限 12.5MB,防止超限绕过
SecResponseBodyAccess Off
SecAuditEngine RelevantOnly # 仅记录命中规则的请求
SecAuditLog /var/log/modsec_audit.log
SecDefaultAction "phase:1,log,auditlog,deny,status:403"
三、部署 OWASP CRS 核心规则集
CRS 需要配合 ModSecurity 的配置一起使用,先克隆规则集并初始化:
git clone --depth 1 https://github.com/coreruleset/coreruleset.git /etc/nginx/modsec/crs
cd /etc/nginx/modsec/crs
cp crs-setup.conf.example crs-setup.conf
# 在 crs-setup.conf 中建议开启:
# SecDefaultAction "phase:1,deny,log,status:403"
# -- 开启 Paranoia Level 1(默认),生产环境先用 1,稳定后再逐步提高
接着在 ModSecurity 主配置末尾引入 CRS 规则文件:
# modsecurity.conf 末尾追加
Include /etc/nginx/modsec/crs/crs-setup.conf
Include /etc/nginx/modsec/crs/rules/*.conf
规则文件按顺序加载,其中 REQUEST-942-APPLICATION-ATTACK-SQLI.conf 负责 SQL 注入检测,REQUEST-941-APPLICATION-ATTACK-XSS.conf 负责 XSS 检测,REQUEST-913-SCANNER-DETECTION.conf 负责识别扫描器指纹(如 sqlmap、nikto)。
四、站点接入 WAF 并验证拦截效果
在需要防护的 server 块中开启 modsecurity 并指定配置:
server {
listen 443 ssl;
server_name www.example.com;
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;
location / {
proxy_pass http://127.0.0.1:8080; # 后端站点
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
# 测试配置并重载
nginx -t && nginx -s reload
用包含典型攻击特征的请求验证拦截是否生效(以下写法已省略完整攻击特征,避免示例本身被防护系统拦截,实际验证时按常规教学资料构造即可):
# 1) SQL 注入恒真条件特征(预期返回 403)
curl -I "https://www.example.com/?id=1%20OR%201=1"
# 2) XSS 标签特征(预期返回 403,此处仅示意占位)
curl -I "https://www.example.com/?q=script标签特征占位"
# 3) 扫描器 UA 特征(预期返回 403)
curl -I -A "sqlmap/1.7" "https://www.example.com/"
如果返回 403 并在 /var/log/modsec_audit.log 中看到对应命中记录,说明 WAF 已经正常工作。建议先在 DetectionOnly 模式下观察 1-2 天,确认没有误伤正常业务后再切换为 On 模式正式拦截。
五、规则调优:处理误报与白名单
CRS 默认级别对正常业务总体友好,但仍可能出现误报,常见处理方式有三种:
# 1. 按 URL 放行(如富文本编辑器、上传接口)
SecRule REQUEST_URI "@beginsWith /wp-admin/post.php" "id:100001,phase:1,pass,nolog,ctl:ruleEngine=Off"
# 2. 按规则 ID 排除(先查审计日志拿到误报规则 ID,再精准排除)
SecRuleRemoveById 942100
# 3. 对可信 IP 直接放行
SecRule REMOTE_ADDR "@ipMatch 1.2.3.4" "id:100002,phase:1,pass,nolog,ctl:ruleEngine=Off"
调优的原则是:能精确到规则 ID 就不整站关闭,能按 URL/IP 圈定就不全局放行,始终保留审计日志以备溯源。
总结
自建 WAF 的成本几乎为零,ModSecurity + OWASP CRS 完全可以满足中小站点的应用层防护需求,关键是把”安装 → 接入 → 验证 → 调优”这四步走完,并定期更新规则集(git pull 即可)。需要提醒的是,WAF 只解决应用层攻击,面对大流量 DDoS 和高压 CC 攻击,源站带宽和连接数很快就会被打满,这类场景建议把防护前置到 CDN + WAF 云防护节点,隐藏源站 IP、就近清洗流量。速度网络提供高防 CDN、DDoS/CC 防护与 WAF 规则代维服务,源站 IP 隐藏、攻击流量全清洗,业务零中断,有需要的站长可以联系了解。
