13.1 WAF (Web 应用防火墙)
一句话
WAF 是 “用规则/模型挡 Web 攻击” 的中间层:它挡的是 SQL 注入、XSS、路径穿越这类 “请求层攻击”,挡不住 DDoS 流量与业务逻辑漏洞;用它的关键不是 “开启”,而是 “规则分级 + 误报治理”。
三种部署形态
| 形态 | 做法 | 优点 | 缺点 |
|---|---|---|---|
| 反向代理型 | Nginx + ModSecurity / 云 WAF | 集中、易升级 | 多一跳、需处理 TLS |
| 插件/模块型 | 应用内 SDK/Filter | 低延迟、能看业务上下文 | 侵入、语言绑定 |
| 云 WAF(SaaS) | DNS/CNAME 接入 | 免运维、带情报 | 依赖厂商、数据出境风险 |
实测:小规则集的误报与漏报
4 条良性请求 + 4 条攻击请求,三条朴素规则(含 '、<script、../):
| 结果 | 例子 |
|---|---|
| 误报 1 条 | GET /search?q=O'Reilly(正常输入含单引号) |
| 漏报 1 条 | GET /p?q=%3Cscript%3Ealert(1)%3C/script%3E(URL 编码绕过) |
两个教训:① 规则越简单,误报越高(把正常输入当攻击);② 不做解码就会漏报(编码后的 payload 绕过字符串匹配)。所以 WAF 必须 “先规范化/解码,再匹配”,并允许 “观察模式” 收集误报。
# ModSecurity + OWASP CRS 的最小接入(观察模式先行)
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/main.conf;
# SecRuleEngine DetectionOnly → 只记录不阻断,先看误报
规则分级与治理
| 级别 | 动作 | 适用 |
|---|---|---|
| 观察(DetectionOnly) | 记录命中,不阻断 | 新规则上线、新业务接入 |
| 阻断(On) | 返回 403 | 高置信规则(SQLi/XSS 明确特征) |
| 挑战 | JS 挑战/验证码 | 疑似 bot/CC |
| 限速 | 按 IP/接口限流 | 高频访问 |
反模式
| 反模式 | 后果 |
|---|---|
| 直接全量阻断 | 正常用户被误杀,投诉激增 |
| 不做解码/规范化 | 编码 payload 绕过 |
| 把 WAF 当 DDoS 防护 | 带宽被打满时 WAF 也没机会工作(见 13.2 DDoS 防护) |
| 规则只加不减 | 误报累积,运维不敢开阻断 |
| 不记录命中详情 | 无法定位 “为什么被拦” |
| 用 WAF 替代代码里的参数化查询 | 注入仍可能从其他入口进来 |
三条铁律
🔑 WAF 是纵深防御的一层,不是唯一防线。
🔑 先观察、后阻断;误报要能定位、能豁免。
🔑 必须解码后再匹配,否则绕过成本极低。
自检
Q1 为什么 O'Reilly 会被朴素规则误判?
▸ 答案:因为规则只检查 “是否含单引号”,而单引号在正常文本里合法(人名、搜索词)。WAF 需要上下文与语法分析(如 “引号是否闭合、是否构成 SQL 语法”),而不是简单字符串匹配;否则误报率会高到不可用。
Q2 URL 编码的 XSS 为什么能绕过?
▸ 答案:因为规则匹配的是原始字符串:%3Cscript%3E 里没有 <script 字样,字符串匹配失败。WAF 必须先做 URL 解码/HTML 实体解码,再匹配;多层编码还要递归解码。
Q3 WAF 能挡住 “业务逻辑漏洞” 吗?
▸ 答案:不能:比如 “越权查看他人订单”“优惠券重复使用”,请求语法完全合法,WAF 无法判断业务语义。这类要靠权限校验、幂等、业务风控(见 38.3 授权)。
Q4 为什么 WAF 不能替代 DDoS 防护?
▸ 答案:因为 DDoS 是流量/连接层的攻击:带宽被打满、SYN 队列被打爆时,请求根本到不了 WAF。WAF 只在 “请求能到达应用层” 时有效;抗 DDoS 要靠清洗/anycast/限流(见 13.2 DDoS 防护)。
Q5 观察模式的数据怎么用?
▸ 答案:用它统计规则命中与误报:哪些规则命中最多、哪些命中的是正常业务;据此调规则(加白名单/降级/删除),再把高置信规则切到阻断。没有观察期直接阻断,等于拿用户做实验。
Q6 WAF 放在 TLS 终结前还是后?
▸ 答案:通常在 TLS 终结后(能看到明文才能检查内容);若放在前面,只能看 SNI/元数据,无法检查 payload。代价是 WAF 节点要持有证书,需要严格的密钥管理(见 13.4 密钥与凭证管理)。
Q7 怎么验证 WAF 真的生效?
▸ 答案:三条:攻击样例被拦(返回 403 且日志有命中)、正常业务不被拦(回归/灰度验证)、绕过尝试被处理(编码、分块、多参数污染)。只测第一条,容易得到 “看起来生效” 的假象。