5.14 Web 应用防火墙:ModSecurity + OWASP CRS 配置指南
预计阅读时间:17 分钟
📖 目录
5.1:Linux 安全加固 的安全加固主要针对服务器操作系统层。Web 应用层需要额外的防护——WAF(Web Application Firewall)拦截 SQL 注入、XSS、路径穿越等应用层攻击。ModSecurity 是开源 WAF 引擎,配合 OWASP Core Rule Set(CRS)提供企业级防护。
学习目标
- 理解 WAF 与操作系统安全加固的边界,明确 ModSecurity + OWASP CRS 在 Web 应用防护中的定位
- 能在 Nginx 中集成 ModSecurity(编译连接器与动态模块两种方式)并加载 OWASP CRS 规则集
- 能区分 DetectionOnly 与 On 两种运行模式,并理解各自的适用场景
- 能用 curl 构造 SQL 注入、XSS、路径穿越载荷验证拦截效果,并解读审计日志中的规则命中
- 能通过 SecRuleUpdateTargetById 等指令对误报做参数级、路径级白名单调优
- 能评估 ModSecurity 的性能开销,识别常见绕过手段并规划独立 WAF 层架构
前置知识
- 3.4:Nginx Web服务器 Nginx Web 服务器配置与管理——ModSecurity 以 Nginx 动态模块方式集成,需熟悉 server/location 配置
- 5.1:Linux 安全加固 Linux 安全加固——操作系统层加固与 Web 应用层防护构成纵深防御
- 3.11:SSL/TLS 证书管理 SSL/TLS 证书管理——HSTS 与 HTTPS 强制跳转是抵御 WAF 降级绕过的前提
- ids01 IDS/IPS:Snort/Suricata——网络层入侵检测与 Web 应用层防护的边界与分工
ModSecurity 架构
ModSecurity 可作为 Nginx 模块运行(嵌入式模式):
请求 → Nginx → ModSecurity 引擎 → OWASP CRS 规则检查
↓
拦截(返回 403)/ 仅记录(Detection Only)
↓
允许通过 → 后端应用
| 模式 | 行为 | 适用 |
|---|---|---|
| DetectionOnly | 仅记录告警,不拦截请求 | 初始部署、规则调优 |
| On | 匹配规则时拦截(返回 403) | 生产环境 |
OWASP CRS 规则集详解
CRS(Core Rule Set)按攻击类型划分规则 ID 段,理解分段才能快速定位拦截原因与调优方向:
| 规则段 | 攻击类型 | 典型规则 |
|---|---|---|
| 900xxx | 初始化与异常检测 | 901200 自动多字节编码解码 |
| 910xxx | IP 信誉(恶意客户端黑名单) | 910000 已知恶意客户端 |
| 911xxx | 请求方法强制 | 911000 非法方法拦截 |
| 920xxx | 协议与请求规范 | 920171 GET/HEAD 携带 Transfer-Encoding(分块绕过检测) |
| 921xxx | 协议攻击 | 921110 HTTP 参数污染(HPP) |
| 930xxx | LFI(本地文件包含) | 930120 路径穿越(../) |
| 931xxx | RFI(远程文件包含) | 931130 远程文件包含探测 |
| 932xxx | RCE(远程代码执行) | 932160 Unix 命令注入 |
| 933xxx | PHP 注入 | 933210 PHP 函数调用 |
| 934xxx | Node.js / Java 注入 | 934100 Java 反序列化 |
| 941xxx | XSS(跨站脚本) | 941100 基本 XSS 特征 |
| 942xxx | SQLi(SQL 注入) | 942100 经典 SQL 注入、942200 注释绕过 |
| 943xxx | 会话固定 | 943120 会话 ID 篡改 |
SecAnomalyScoreThreshold(默认 5)才拒绝。所以偶发命中 Notice 级规则不会误杀请求——这正是调优的关键杠杆。# crs-setup.conf 中常用的初始化配置段
# 1) 设置默认 HTTP 策略(允许的 HTTP 方法、协议版本)
SecAction "id:900200,phase:1,nolog,pass,\
setvar:'tx.allowed_methods=GET HEAD POST OPTIONS PUT DELETE PATCH'"
# 2) 指定受保护的应用静态资源后缀(文本/JSON 会被做响应体检查)
SecAction "id:900240,phase:1,nolog,pass,\
setvar:'tx.allowed_request_content_type=application/x-www-form-urlencoded|multipart/form-data|application/json|application/xml'"
# 3) 请求体大小限制(默认 1MB,上传接口按需放宽)
SecAction "id:900250,phase:1,nolog,pass,\
setvar:'tx.max_request_body_size=1MB'"
# 4) 需要额外保护的应用(如 phpMyAdmin)可单独声明
SecAction "id:900260,phase:1,nolog,pass,\
setvar:'tx.protected_asset=phpMyAdmin'"
1. 安装 ModSecurity(Nginx 集成)
方式一:编译 Nginx + ModSecurity(推荐)
# 编译 ModSecurity 连接器
git clone --depth 1 https://github.com/SpiderLabs/ModSecurity
cd ModSecurity
git submodule init
git submodule update
./build.sh
./configure
make -j$(nproc)
sudo make install
# 编译 Nginx 并集成 ModSecurity 模块
wget http://nginx.org/download/nginx-1.26.tar.gz
tar xzf nginx-1.26.tar.gz
cd nginx-1.26
./configure --add-dynamic-module=../ModSecurity/nginx/modsecurity
make modules
sudo cp objs/ngx_http_modsecurity_module.so /etc/nginx/modules/
方式二:使用预编译包
# Ubuntu 通过 PPA(较旧版本)
sudo apt install libmodsecurity-dev nginx-module-modsecurity
# ngx_modsecurity 的替代方案——libmodsecurity3
sudo apt install libmodsecurity3
2. 配置 Nginx
# nginx.conf
load_module modules/ngx_http_modsecurity_module.so;
http {
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/main.conf;
server {
listen 443 ssl;
server_name example.com;
# 按需启用/禁用 ModSecurity(可针对 location)
location /api/ {
# API 端点可能需要更宽松的规则
modsecurity_rules_file /etc/nginx/modsec/api.conf;
}
location /admin/ {
# 管理后台启用严格模式
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/admin.conf;
}
}
}
# /etc/nginx/modsec/main.conf
# 全局配置
Include /etc/nginx/modsec/modsecurity.conf
# OWASP CRS 规则集
Include /etc/nginx/modsec/crs-setup.conf
Include /etc/nginx/modsec/rules/*.conf
# 默认启用,仅记录模式(部署初期)
SecRuleEngine DetectionOnly
# 自定义规则
SecRule REQUEST_URI "@beginsWith /wp-admin" "id:10001,phase:1,deny,status:403,msg:'WordPress admin blocked'"
# /etc/nginx/modsec/modsecurity.conf
SecRuleEngine DetectionOnly
SecRequestBodyAccess On
SecResponseBodyAccess On
SecResponseBodyMimeType text/plain text/html text/xml application/json
SecDataDir /tmp/modsecurity
# 请求体大小限制(防止大 POST 攻击)
SecRequestBodyLimit 10485760 # 10MB
SecRequestBodyNoFilesLimit 131072 # 128KB
# 审计日志
SecAuditEngine RelevantOnly
SecAuditLog /var/log/modsec/audit.log
SecAuditLogFormat JSON
3. 安装 OWASP CRS
# 下载 CRS
git clone --depth 1 https://github.com/coreruleset/coreruleset /etc/nginx/modsec/crs
# 复制配置模板
cp /etc/nginx/modsec/crs/crs-setup.conf.example \
/etc/nginx/modsec/crs-setup.conf
# 包含规则文件
echo 'Include /etc/nginx/modsec/crs/rules/*.conf' \
>> /etc/nginx/modsec/main.conf
# 测试配置
nginx -t
# 重启 Nginx
systemctl reload nginx
安装三步总览
| 步骤 | 操作 | 验证命令 |
|---|---|---|
| ① 安装 ModSecurity 引擎 | 编译连接器 + Nginx 动态模块 | nginx -V 2>&1 | grep modsecurity |
| ② 配置 Nginx 加载模块 | load_module + modsecurity_rules_file | nginx -t 无报错 |
| ③ 部署 CRS 规则集 | 下载 coreruleset、配置 crs-setup.conf | 发送测试 payload 命中审计日志 |
注意版本兼容性:CRS 4.x 需要 ModSecurity 2.9.5+ 或 3.0.x;老教程把 SecRuleEngine 写在 crs-setup.conf 的写法在 CRS 4 中已废弃,统一由 modsecurity.conf 管理,混用会导致规则不生效。
4. 测试 WAF 拦截
# SQL 注入测试——应被拦截
curl -v 'https://example.com/search?q=1%27%20OR%20%271%27%3D%271'
# XSS 测试
curl -v 'https://example.com/search?q=%3Cscript%3Ealert(1)%3C/script%3E'
# 路径穿越
curl -v 'https://example.com/download?file=../../../etc/passwd'
# 查看审计日志
tail -f /var/log/modsec/audit.log | jq '.'
# 示例输出(JSON 格式):
# {
# "transaction": {
# "messages": [{
# "ruleId": "942100",
# "message": "SQL Injection Detected",
# "severity": "CRITICAL",
# "uri": "/search?q=1' OR '1'='1"
# }]
# }
# }
攻击 payload 与拦截日志对照
| 攻击 | 测试 payload | 命中规则 | 日志关键字段 |
|---|---|---|---|
| SQL 注入 | /search?q=1%27%20OR%20%271%27%3D%271 | 942100 / 942130 | msg: "SQL Injection Attack Detected" |
| SQL 注释绕过 | /search?q=1%27%20UNION%20SELECT%20...%23 | 942200 | ruleId: 942200 |
| XSS | /search?q=%3Cscript%3Ealert(1)%3C%2Fscript%3E | 941100 | msg: "XSS Attack Detected" |
| 路径穿越 | /download?file=..%2F..%2Fetc%2Fpasswd | 930120 | severity: CRITICAL |
| 命令注入 | /api?host=127.0.0.1%3Bcat%20%2Fetc%2Fpasswd | 932160 | msg: "Remote Command Execution" |
# 审计日志中的完整命中记录(DetectionOnly 模式下仅记录不拦截)
# tail /var/log/modsec/audit.log | jq '.transaction.messages[]'
{
"ruleId": "942100",
"message": "SQL Injection Attack Detected via libinjection",
"severity": "CRITICAL",
"uri": "/search?q=1' OR '1'='1",
"data": "Matched Data: '1' OR '1'='1' found within ARGS:q"
}
# 解读:data 字段给出命中的参数(ARGS:q)与特征值——调优时据此定位目标参数
拦截响应示例(On 模式)
# 开启拦截模式后,命中规则返回 403:
$ curl -v 'https://example.com/search?q=1%27%20OR%20%271%27%3D%271'
HTTP/1.1 403 Forbidden
Content-Type: text/html
Server: nginx/1.26
<html><body>Request blocked by ModSecurity</body></html>
# 同时审计日志记录本次拦截的完整上下文:
# jq '.transaction' /var/log/modsec/audit.log | jq '{id, client_ip, messages}'
{
"id": "Q1W2E3R4T5",
"client_ip": "203.0.113.44",
"messages": [
{
"ruleId": "942100",
"message": "SQL Injection Attack Detected via libinjection",
"severity": "CRITICAL"
},
{
"ruleId": "949110",
"message": "Inbound Anomaly Score Exceeded",
"severity": "CRITICAL"
}
]
}
# 注意 949110:当累计异常分超过阈值时由它执行最终拦截——
# 单条规则可以命中,但真正决定「拦不拦」的是总分数
5. 误报调优
OWASP CRS 规则集默认很严格,容易误伤正常请求。调优流程:
# 第一步:DetectionOnly 模式观察一周
# 收集所有违规请求到日志,标记误报和真实攻击
# 第二步:为误报创建白名单
# /etc/nginx/modsec/crs-setup.conf(添加在文件末尾)
# 排除特定参数的规则
SecRuleUpdateTargetById 942100 "!ARGS:password"
SecRuleUpdateTargetById 942100 "!ARGS:token"
# 排除特定路径
SecRuleUpdateTargetById 933210 "!REQUEST_URI:/api/v2/"
# 降低某规则严重性(从 CRITICAL 降为 NOTICE)
SecRuleUpdateActionById 942100 "phase:2,pass,log,severity:NOTICE"
# 第三步:逐步开启 Blocking 模式
# 先对低风险路径启用 On
# /etc/nginx/modsec/rules/custom_blocking.conf
SecRule REQUEST_URI "@beginsWith /api/public" "id:20001,phase:1,ctl:ruleEngine=On"
# 第四步:观察一段时间后全局切换为 On
SecRuleEngine On
完整调优手段对比
| 手段 | 指令 | 适用场景 |
|---|---|---|
| 移除单条规则 | SecRuleRemoveById 942100 | 确定某规则与业务冲突(全局移除需谨慎) |
| 指定目标豁免 | SecRuleUpdateTargetById 942100 "!ARGS:q" | 仅对特定参数/路径豁免,保留其余检查(首选) |
| 降低严重度 | SecRuleUpdateActionById 942100 "severity:NOTICE" | 命中真实但危害低,保留日志不拦截 |
| 提高异常分阈值 | SecAnomalyScoreThreshold 10 | 业务请求常积累 3-4 分被误杀时整体放宽 |
| 按内容类型豁免 | SecRuleUpdateTargetById 942100 "!REQUEST_BODY" | JSON API 传富文本时按请求体豁免 |
# Paranoia Level(偏执等级)——更推荐的调优起点
# PL1:默认,只查明确攻击特征,误报率低(建议上线起点)
# PL2:增加弱特征规则,误报率上升
# PL3/PL4:规则数量翻倍,用于严格合规场景
# crs-setup.conf 中修改:
SecAction \
"id:900000,phase:1,nolog,pass,t:none,\
setvar:tx.executing_paranoia_level=2"
# 按路径应用不同策略(富文本 API 放宽,登录页收紧)
SecRule REQUEST_URI "@beginsWith /api/content" \
"id:20002,phase:1,pass,ctl:ruleEngine=DetectionOnly,ctl:removeById=942100"
# 误报申诉流程:收到用户 403 反馈 → 查日志确认命中规则 →
# 与业务确认是否误报 → 写白名单(留注释说明原因与责任人)→ 走 Git 变更
SecRuleUpdateTargetById 做参数级豁免 → ③ 仍误杀再降严重度或移除规则 → ④ 全局性误杀才动异常分阈值或 Paranoia Level。WAF 部署模式
ModSecurity 有三种部署形态,决定故障域与绕过风险:
| 模式 | 形态 | 优点 | 风险 |
|---|---|---|---|
| 嵌入式(串联) | 作为 Nginx 模块运行在业务入口 | 零额外网络链路、部署简单 | WAF 故障 = 业务故障;规则绕过直接暴露应用 |
| 独立反向代理(串联) | 独立 WAF 节点串在入口与后端之间 | 故障域隔离、可横向扩容 | 多一跳网络延迟;需保证 WAF 节点高可用 |
| 镜像/旁路(TAP) | 流量复制到 WAF 分析 | 完全不影响线上流量 | 只能检测不能实时拦截 |
# 独立 WAF 节点部署拓扑
客户端 → (443) → 入口 LB → WAF 节点(Nginx+ModSecurity) → 业务 Nginx → 应用
│
└─ 仅 WAF 节点加载 modsecurity,业务节点零开销
# 旁路(镜像)模式示例——Nginx mirror 复制流量,WAF 只读不改
server {
listen 443 ssl;
mirror /waf_mirror;
mirror_request_body on;
}
location = /waf_mirror {
internal;
proxy_pass http://waf-cluster:8080$request_uri;
}
# 该模式下 WAF 的拦截动作对用户不可见,只用于分析真实流量特征
# 检测 → 拦截的切换节奏:
# 第 1-2 周:全局 DetectionOnly(收集基线)
# 第 3 周:/login、/api/public 等低风险路径 On
# 第 4 周:除富文本接口外全局 On
# 持续:异常请求量突增时临时提高 Paranoia Level
6. ModSecurity 性能影响
| 配置 | QPS 影响 | 延迟增加 |
|---|---|---|
| CRS + 请求体检测 | -20% ~ -30% | ~5-15ms |
| CRS 仅 URL / 头部检测 | -10% ~ -15% | ~2-5ms |
| 自定义规则(简单) | -2% ~ -5% | ~1ms |
性能调优清单
| 调优项 | 建议 | 说明 |
|---|---|---|
| 请求体检测范围 | 仅对 POST/PUT 路径开启 SecRequestBodyAccess | GET 请求体检测纯属浪费 CPU |
| 静态资源豁免 | 对 /static/ /img/ 使用 modsecurity off | 图片/CSS 不会被注入攻击,省掉一半检测量 |
| 响应体检测 | SecResponseBodyAccess Off | 响应检测收益低且消耗大,默认关闭 |
| 审计日志策略 | SecAuditEngine RelevantOnly | 只记录命中请求,避免磁盘写满 |
| 连接复用 | WAF 节点与后端启用 keepalive | 降低每请求新建连接开销 |
| 水平扩容 | WAF 无状态,多节点 + LB 轮询 | CPU 饱和后直接加节点,无需粘性会话 |
7. 常见绕过与防御
| 绕过方式 | 防御 |
|---|---|
| URL 编码双写(%253C 绕过 %3C) | CRS 901200 自动多字节解码(解码后按原始数据再检测) |
| 分块传输(Chunked Transfer) | CRS 920171/920180 协议强制段校验 Transfer-Encoding |
| Content-Type 混淆 | CRS 920420 检测非白名单 Content-Type |
| HTTP 参数污染(HPP) | CRS 规则 921100-HPP |
| HTTPS 降级 | HSTS 策略 + HTTP 强制跳转 HTTPS |
8. 告警接入与规则生命周期
WAF 的价值在于"拦截了攻击"这件事必须被看见:日志要进集中存储、命中要触发告警、规则要能迭代。三个环节都自动化,WAF 才不是摆设。
审计日志接入集中存储
# 1. modsecurity.conf 中开启 JSON 审计日志(前文已配置)
# SecAuditLog /var/log/modsec/audit.log + SecAuditLogFormat JSON
# 2. Promtail(Loki)采集配置:按文件名过滤 + JSON 解析
# promtail-config.yml
scrape_configs:
- job_name: modsec
static_configs:
- targets: [localhost]
labels: { job: modsec }
pipeline_stages:
- json:
expressions:
transaction: transaction
severity: transaction.messages[0].severity
rule_id: transaction.messages[0].ruleId
- labels: { rule_id: rule_id, severity: severity }
# 3. 告警规则(Loki 查询,5 分钟窗口)
# - alert: WAF_Attack_Burst
# expr: sum(count_over_time({job="modsec"}[5m])) > 20
# annotations:
# summary: "5 分钟内 WAF 命中 {{ $value }} 次"
命中量突增要能区分两种信号:攻击在打你(同一 IP / 同一规则高频命中——多半是扫描器,直接封禁)与规则在误杀(不同用户、不同参数命中同一规则——触发调优流程)。用 Loki/ES 按 rule_id + client_ip 分组统计即可快速区分。
规则即代码:CRS 与自定义规则入 Git
# 仓库结构
waf-rules/
├── crs/ # 上游 CRS(版本固定,升级走 PR)
├── custom/ # 自定义规则(按业务拆分)
│ ├── 10001-wp-admin.conf
│ └── 10002-rate-limit.conf
├── whitelist/ # 误报豁免(每条附注释:原因 + 责任人 + 日期)
│ └── 2025-06-search-whitelist.conf
└── tests/
└── payloads.txt # 回归载荷集(攻击载荷 + 正常载荷)
# 回归测试脚本:变更规则后自动验证
# waf-test.sh —— 对测试环境跑全部载荷,统计漏报与误杀
while IFS= read -r line; do
case "$line" in
ATTACK:*) code=$(curl -s -o /dev/null -w "%{http_code}" "${line#ATTACK: }")
[ "$code" = "403" ] || echo "漏报: $line (HTTP $code)" ;;
NORMAL:*) code=$(curl -s -o /dev/null -w "%{http_code}" "${line#NORMAL: }")
[ "$code" != "403" ] || echo "误杀: $line" ;;
esac
done < tests/payloads.txt
# 规则变更流程:Git PR → 测试环境跑回归 → 灰度路径观察 1 周 → 合入
IP 封禁与速率限制
# 命中 942100 且 5 分钟内同 IP 3 次 → 封禁 1 小时(fail2ban)
[modsec-block]
enabled = true
logpath = /var/log/modsec/audit.log
maxretry = 3
findtime = 300
bantime = 3600
filter = fail2ban-filter-modsec
# 或纯 Nginx 限速(防慢速攻击 + 登录爆破)
limit_req_zone $binary_remote_addr zone=waf_login:10m rate=5r/m;
location /login/ {
limit_req zone=waf_login burst=5;
proxy_pass http://backend;
}
9. WAF 的边界:它拦不住什么
WAF 只做"请求内容检查",以下攻击它天然看不见,需要其他防线补齐——理解边界才能把预算花在正确的地方:
| WAF 拦不住的 | 原因 | 补齐手段 |
|---|---|---|
| 业务逻辑漏洞(越权、重放、薅羊毛) | 请求内容完全合法 | 权限模型设计 + 业务风控 |
| 水平越权(改他人 ID 访问数据) | 攻击发生在认证之后 | 应用层对象级授权(OWASP API1) |
| 慢速攻击(Slowloris) | 半连接、极低速率,难以定义"恶意" | Nginx 层限速/连接超时、专业抗 DDoS |
| 加密流量内的攻击(WAF 在 TLS 终结之前) | 看不到明文 | WAF 放在 TLS 终结之后,或旁路解密的流量分析 |
| 内部威胁与批量抓取 | IP 可信、行为异常 | 行为分析、频率限制(见第 8 节告警分组) |
纵深防御的分工:网络层(IDS/IPS、DDoS 防护)→ Web 层(本文的 WAF)→ 应用层(参数化查询、权限校验、RASP)→ 数据层(脱敏、加密、审计)。WAF 是第二道墙,不是全部——把"WAF 有了所以安全了"当结论,是生产事故最常见的开场。
常见错误
| 错误现象 | 可能原因 | 排查方法 |
|---|---|---|
| 所有请求返回 403 | ModSecurity 规则过于严格,或规则加载顺序错误 | 临时切换为 DetectionOnly 模式,查看 /var/log/modsec/audit.log 中具体命中的规则 ID,逐条排除 |
| Nginx 启动失败:module not found | 动态模块路径错误或模块未编译到对应架构 | 确认 /etc/nginx/modules/ 下存在 .so 文件,检查 load_module 路径是否正确,nginx -V 查看编译参数 |
| 请求体检测不生效 | 未启用 SecRequestBodyAccess On 或请求体超过限制 | 检查 modsecurity.conf 中 SecRequestBodyAccess 和 SecRequestBodyLimit 设置 |
| OWASP CRS 规则未加载 | Include 路径缺失或规则文件权限不足 | nginx -t 检查配置语法,确认 crs-setup.conf 和 rules/*.conf 文件存在且 Nginx 用户可读 |
| 正常 API 请求被误拦截 | CRS 默认规则对特殊字符、长参数过于敏感 | 参考第 5 节调优流程,通过 SecRuleUpdateTargetById 为特定参数或路径创建白名单 |
| CRS 升级后误拦激增 | 新版本规则覆盖范围扩大 | 升级后在测试环境跑回归载荷集(见第 8 节),生产先切 DetectionOnly 观察 1 周再恢复拦截 |
| 审计日志写满磁盘 | 高流量下 RelevantOnly 仍产生大量日志 | logrotate 按天轮转并设保留策略;日志同步到集中存储后本地仅留 7 天;SecAuditLogStorageDir 限制单文件大小 |
最佳实践
- 分阶段上线:先 DetectionOnly 运行 1-2 周,充分分析日志后再切换为 Blocking 模式,避免误伤正常用户。
- 按路径分级管控:对外公开 API 使用宽松规则集,管理后台启用严格模式,不同业务区域使用独立的
modsecurity_rules_file。 - 日志结构化:开启
SecAuditLogFormat JSON,便于接入 ELK 或 Loki 进行集中分析和告警。 - 独立 WAF 层:在独立的反向代理层运行 ModSecurity,后端业务 Nginx 不加载 ModSecurity 模块,降低性能影响并简化维护。
- 定期更新 CRS:OWASP CRS 持续发布新规则以应对新攻击向量,建议每月同步上游更新,并在测试环境验证后再部署到生产。
- 规则进 Git 走评审:CRS 版本、自定义规则、白名单豁免全部纳入版本管理,每条豁免注明原因与责任人,升级可回滚。
- 维护回归载荷集:把攻击样例与误报样例沉淀为测试用例,规则变更必跑回归,用漏报/误杀数据说话。
练习题
- 在测试环境中搭建 ModSecurity + OWASP CRS,先以 DetectionOnly 模式运行,使用
curl发送 SQL 注入、XSS、路径穿越三种攻击载荷,记录审计日志中的规则命中情况。 - 为你的 Web 应用的搜索接口(假设参数为
q)编写一条自定义白名单规则,排除ARGS:q参数上的 SQL 注入检测规则 942100,验证白名单生效后正常搜索不再被拦截。 - 编写一条 ModSecurity 自定义规则,拦截所有尝试访问
/backup目录的请求并返回 403,记录规则 ID 和拦截消息到审计日志。 - 搭建告警链路:把 ModSecurity 审计日志接入 Loki(或 ELK),配置"5 分钟内命中超过 20 次"的告警,分别用扫描器流量与正常流量验证告警触发与不触发。
- 为你的业务梳理一份"WAF 边界清单":列出 WAF 拦不住的 3 类风险及对应的补齐手段,形成一页纸的纵深防御分工表。
学习检查点
学完本章后,请检验自己是否掌握以下内容:
| 检查项 | 自测问题 | 验证方法 |
|---|---|---|
| 概念理解 | 能用自己的话解释 WAF 的工作原理和 OWASP Top 10 防护 | 尝试向他人讲解 |
| 命令操作 | 能不查文档完成 ModSecurity/Coraza 规则编写和部署 | 在终端实际执行 |
| 原理掌握 | 能说出 WAF 的正向代理模式和反向代理模式的区别 | 画出流程图 |
| 故障排查 | 能独立排查 WAF 误拦截正常请求的问题 | 模拟故障并修复 |
| 最佳实践 | 能说明为什么需要对 WAF 规则进行持续调优 | 对比不同方案 |
本章总结
WAF 补齐了操作系统加固无法覆盖的应用层防线:ModSecurity + OWASP CRS 能拦截 SQL 注入、XSS、路径穿越等常见攻击,但默认规则严格,直接开启 Blocking 模式必然误伤正常业务。正确路线是 DetectionOnly 观察、白名单调优、按路径分级、逐步切换到拦截模式,并把 WAF 部署在独立反向代理层控制性能开销。WAF 只是纵深防御的一环,需与 TLS 强化、IDS/IPS 协同使用。
延伸阅读
- 3.4:Nginx Web服务器 Nginx Web 服务器配置与管理
- 3.11:SSL/TLS 证书管理 SSL/TLS 证书管理(HSTS 与 HTTPS 强化)
- 5.1:Linux 安全加固 Linux 安全加固(操作系统层安全)