
我坐在香港机房冷气呼呼直吹的机柜前,盯着接入层交换机不断刷新的 NetFlow 记录:数以万计的请求正跨海而来。一次突发的 SQL 注入拉高了后端 MySQL 的 CPU——虽未酿成事故,却让我彻底警觉。外部云 WAF 在极端高并发场景下偶有抖动,加之对自定义规则的灵活性不足,我决定 亲自为香港服务器栈部署本地化 WAF,既要挡住 SQLi、XSS,也要保证微秒级延迟不被拖慢。以下记录的是全过程的踩坑与优化细节。
环境与目标
| 组件 | 版本 | 说明 |
|---|---|---|
| OS | AlmaLinux 9.4 (4.18 内核) | 最小化安装,关闭 SELinux |
| Web 服务器 | Nginx 1.26.0(源码编译) | 作为反向代理/边缘网关 |
| WAF 引擎 | ModSecurity v3 + OWASP CRS 4.0.0 | 动态模块方式接入 Nginx |
| 监控 | Prometheus 2.52 + Grafana 11 | 自定义 Exporter 采集 WAF metrics |
| 硬件 | 香港 A5 数据 E5-2680v4 ×2 / 128 GB / NVMe RAID1 / 10 Gbps UpLink | 单臂部署在 DMZ |
目标指标
- SQLi、XSS 检测规则在 Paranoia Level 2 下误报率 < 0.05 %。
- 单节点吞吐 ≥ 25 000 RPS,99-pct 延迟增加 ≤ 1 ms。
- WAF 规则更新 < 5 min 自动上线,可随时回滚。
1. 架构选型:本地内嵌 vs. 独立反代
本地内嵌(Nginx 动态模块)
优点:零额外网络跳数、延迟最低;缺点:Nginx 崩溃风险放大。
独立反向代理
优点:进程隔离、规则热更新更安全;缺点:多一次网络转发。
我最终采用 “主节点内嵌 + 灾备独立反代” 的混合模式:生产流量经内嵌,切换开关由 DNS-TXT + Consul KV 控制,必要时 5 s 内漂移到备用反代节点。
2. 构建 ModSecurity v3 动态模块
# 安装依赖
dnf -y groupinstall "Development Tools"
dnf -y install git gcc-c++ libxml2-devel yajl-devel lmdb-devel \
ssdeep-devel geoip-devel libcurl-devel
# 编译 libmodsecurity
cd /usr/local/src
git clone --depth 1 https://github.com/SpiderLabs/ModSecurity
cd ModSecurity
git submodule update --init --depth 1
./build.sh && ./configure --prefix=/opt/modsecurity \
--enable-lmdb --enable-geoip
make -j$(nproc) && make install
# 编译 Nginx 并挂载模块
wget https://nginx.org/download/nginx-1.26.0.tar.gz
tar zxvf nginx-1.26.0.tar.gz && cd nginx-1.26.0
git clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx
./configure --prefix=/opt/nginx \
--with-compat \
--add-dynamic-module=./ModSecurity-nginx \
--with-stream --with-http_ssl_module
make modules && cp objs/ngx_http_modsecurity_module.so /opt/nginx/modules/
make && make install
实测:动态模块方式比静态编译节省 60 % 重新发布时间,且升级 Nginx 小版本只需重新 make modules。
3. 部署 OWASP Core Rule Set(CRS)
cd /opt/nginx/conf
git clone --depth 1 https://github.com/coreruleset/coreruleset crs
mv crs/crs-setup.conf.example crs/crs-setup.conf
Paranoia Level:生产先设为 2,监控一周后再考虑提到 3。
插件规则:开启 REQUEST-944-APPLICATION-ATTACK-SQLI.conf 与 REQUEST-941-APPLICATION-ATTACK-XSS.conf;其他高误报模块(如 949 等)暂置为 log。
4. Nginx-WAF 集成配置
load_module modules/ngx_http_modsecurity_module.so;
events { worker_connections 4096; }
http {
modsecurity on;
modsecurity_rules_file /opt/nginx/conf/modsec/main.conf;
# 防止日志阻塞
modsecurity_transaction_cache shm:modscache:50m;
server {
listen 443 ssl http2 reuseport;
server_name app.example.hk;
ssl_certificate /etc/pki/tls/certs/app.pem;
ssl_certificate_key /etc/pki/tls/private/app.key;
# CSP 附加防 XSS
add_header Content-Security-Policy "default-src 'self'" always;
location / {
proxy_pass http://backend_pool;
proxy_set_header X-Real-IP $remote_addr;
}
}
}
/opt/nginx/conf/modsec/main.conf 关键段落:
Include "/opt/nginx/conf/crs/crs-setup.conf"
Include "/opt/nginx/conf/crs/rules/*.conf"
# 自定义 SQLi 黑名单绕过
SecRule REQUEST_URI "@rx (?i)(union(.*?)select|load_file|\bconcat\b)" \
"id:10010,phase:2,log,deny,status:403,msg:'Manual SQLi rule'"
# 自定义 XSS 关键字检测
SecRule ARGS "@rx (?i)(<script|onerror=|onload=|alert\(1\))" \
"id:10020,phase:2,log,deny,status:403,msg:'Manual XSS rule'"
5. 性能调优要点
缓存事务数据
- modsecurity_transaction_cache shm:modscache:50m 能显著减小碎片化内存复用延迟。
只解析必要的请求体
- 在 REQUEST-920-PROTOCOL-ENFORCEMENT.conf 中关闭 XML/Multipart 解析,避免大文件上传时 CPU 飙升。
编译参数
- -O3 -march=native 比默认提升约 7 % 吞吐;同时开启 Nginx reuseport 充分利用多核。
NUMA 亲和
- 使用 numactl –cpunodebind=0 –membind=0 启动主进程,可降低内存跨 NUMA 访问。
6. 监控与告警
6.1 日志格式
SecAuditLogFormat JSON
SecAuditLog /var/log/modsec/audit.log
6.2 Prometheus Exporter
自写 Go Exporter,通过 tail 审计日志解析指标:
| Metric | 解释 |
|---|---|
modsec_requests_total |
所有经 WAF 请求数 |
modsec_blocked_total |
被拦截请求数 |
modsec_blocked_sqli_total / xss_total |
按攻击类型拆分 |
示例 Alertmanager 规则:(假设 5 min 阈值)
- alert: WAFHighBlockRate
expr: (sum(rate(modsec_blocked_total[5m])) / sum(rate(modsec_requests_total[5m]))) > 0.05
for: 5m
labels:
severity: warning
annotations:
summary: "WAF 阻断率异常升高"
7. CI/CD:规则与配置自动化
GitLab CI:
- Push 触发 modsec-lint,通过 modsec-parser.py 校验语法;
- 生成差异补丁,打包成 RPM;
- SaltStack 绑定 TAG 推送到香港节点;
- Nginx ngx_http_api_module 热加载模块,无需重启。
回滚:保留最近三版 RPM,通过 SaltStack pkg.install version=<x> 即可恢复。
8. 压力与渗透测试
| 工具 | 场景 | 目标 |
|---|---|---|
| wrk2 | 10 k 并发、300 MB/s | 延迟基线 |
| sqlmap | UNION-based/Time-based | SQLi 拦截率 |
| OWASP ZAP | 自动化 XSS 脚本注入 | XSS 拦截率 |
| GoReplay | 线上流量镜像 | 误报分析 |
在 25 000 RPS、平均包体 2 KB 的实测下,CPU 利用率约 68 %,P99 延迟增加 0.74 ms。
9. 运营防护 SOP
- 实时看板:Grafana 监控大盘滚动投屏,关键指标一目了然。
- 误报处理:拦截日志自动流入 Loki,开发自助点击放行;同时记录 modsec_id 进入白名单文件。
- 应急旁路:HAProxy 支持基于 Consul KV 的 ACL 开关,一键绕过 WAF 直通后端。
- 月度审计:结合 Nessus + Burp Suite,对规则库做差异扫描并生成报告。
三周的持续调优后,SQL 注入与 XSS 攻击被拦截 23 486 次,误报仅 9 次。在香港这一高速跨境节点,本地化 WAF 成功兼顾了低延迟与高安全。接下来,我计划:
- 引入 机器学习异常检测 提前识别零日 Payload;
- 将规则仓库与 Semgrep 静态扫描结合,自动发现新模式;
- 对接 eBPF 流控实现更细粒度 Layer 7 速率限制。
希望我的亲历记录能为你在香港或其他高流量机房部署 WAF 提供参考。只要策略得当,开源方案一样能构筑企业级的第一道攻防壁垒。











