上一篇讲了 DDoS 防御——它解决的是”把流量打到你扛不住”的问题。WAF(Web Application Firewall,Web 应用防火墙)解决的是另一类问题:攻击者的流量不大,但每一个请求都可能携带恶意 payload——SQL 注入、XSS、命令注入、路径遍历。WAF 的核心挑战不是性能,而是精度:怎么在不影响正常业务的前提下拦截恶意请求。
一、WAF 基础概念
1.1 WAF 的工作位置
WAF 工作在 HTTP 层(OSI 第七层),检查 HTTP 请求和响应的内容。它可以部署在不同的位置:
客户端
│
↓
┌─────────────┐
│ CDN / 云 WAF │ ← 位置 1:云端(Cloudflare WAF、AWS WAF)
└──────┬──────┘
↓
┌─────────────┐
│ 反向代理 WAF │ ← 位置 2:反向代理(ModSecurity + Nginx)
└──────┬──────┘
↓
┌─────────────┐
│ 负载均衡器 │ ← 位置 3:嵌入 LB(F5 ASM)
└──────┬──────┘
↓
┌─────────────┐
│ 应用服务器 │ ← 位置 4:应用内置(RASP)
└─────────────┘
各部署位置的工程权衡:
| 部署位置 | 优点 | 缺点 |
|---|---|---|
| 云端 WAF | 零运维、全球分布、大规模规则库 | 依赖第三方、无法深度定制、延迟 |
| 反向代理 WAF | 灵活定制、开源可控 | 运维成本高、需要维护规则 |
| 嵌入 LB | 一体化管理、性能好 | 厂商锁定、授权费昂贵 |
| RASP | 上下文感知强、零误报 | 侵入应用代码、性能开销 |
1.2 WAF 的检测模型
WAF 的检测逻辑分为两大类:
正向模型(Allowlist / Positive Model):定义”合法请求长什么样”,不匹配的全部拦截。精度极高但配置复杂——需要为每个 API 端点定义合法参数的类型、长度、字符集。
负向模型(Blocklist / Negative Model):定义”恶意请求长什么样”,匹配签名/规则的拦截。配置简单但容易被绕过——攻击者可以通过编码、混淆等方式绕过规则。
大多数 WAF 以负向模型为主,配合正向模型的辅助检查。OWASP CRS 就是负向模型的代表。
二、OWASP CRS 规则体系
2.1 CRS 概述
OWASP Core Rule Set(CRS)是最广泛使用的开源 WAF 规则集。它为 ModSecurity 引擎设计,但概念适用于所有 WAF。CRS 目前的最新版本为 4.x,包含约 200 条核心规则,覆盖 OWASP Top 10 中的大部分攻击类型。
CRS 的分层结构:
CRS 规则编号范围
┌──────────────────────────────────────────────────┐
│ 900xxx 初始化与配置 │
│ 901xxx 请求初始化 │
│ 910xxx Scanner/Bot 检测 │
│ 911xxx Method Enforcement │
│ 912xxx DOS Protection │
│ 913xxx Scanner Detection │
│ 920xxx Protocol Enforcement (请求格式验证) │
│ 921xxx Protocol Attack (HTTP 协议攻击) │
│ 930xxx Local File Inclusion (LFI) │
│ 931xxx Remote File Inclusion (RFI) │
│ 932xxx Remote Code Execution (RCE / 命令注入) │
│ 933xxx PHP Injection │
│ 934xxx Node.js Injection │
│ 941xxx XSS (跨站脚本) │
│ 942xxx SQL Injection (SQL 注入) │
│ 943xxx Session Fixation │
│ 944xxx Java Attacks │
│ 949xxx Blocking Evaluation │
│ 950xxx Outbound (响应检查) │
│ 959xxx Outbound Blocking │
│ 980xxx Correlation (关联分析) │
└──────────────────────────────────────────────────┘
2.2 CRS 的异常评分模型
CRS 使用异常评分(Anomaly Scoring)而非单规则阻断。每条规则匹配时给请求加一个”异常分数”,只有当总分超过阈值时才拦截。这大幅减少了单条规则误报导致的合法请求被拦截:
请求进入
│
├── 规则 942100 匹配 → +5 分(SQL 注入特征)
├── 规则 941100 匹配 → +5 分(XSS 特征)
├── 规则 920350 匹配 → +2 分(Host 头 IP 格式)
│
总分 = 12
│
阈值 = 5 → 拦截
阈值 = 10 → 拦截
阈值 = 15 → 放行(累积不够)
异常分数级别:
| 严重级别 | 默认分数 | 含义 |
|---|---|---|
| CRITICAL | 5 | 高置信度攻击(SQL 注入核心特征) |
| ERROR | 4 | 中等置信度(可疑但有误报可能) |
| WARNING | 3 | 低置信度(异常但可能合法) |
| NOTICE | 2 | 信息级别(记录但几乎不影响评分) |
配置阈值:
# ModSecurity CRS 配置
# crs-setup.conf
# 入站异常评分阈值
# PL1 (Paranoia Level 1) = 5:只拦截高置信度攻击
# PL2 = 5:更多规则启用
# PL3 = 5:激进检测
# PL4 = 5:最严格(几乎不可用于生产)
SecAction "id:900110,phase:1,pass,\
setvar:tx.inbound_anomaly_score_threshold=5,\
setvar:tx.outbound_anomaly_score_threshold=4"
# Paranoia Level(偏执级别)
# PL1:基础规则,低误报(生产推荐起始值)
# PL2:增加规则,中误报
# PL3:激进检测,高误报
# PL4:研究级别,极高误报
SecAction "id:900000,phase:1,pass,\
setvar:tx.paranoia_level=1"
2.3 ModSecurity 规则语法
ModSecurity 是最流行的开源 WAF 引擎。理解其规则语法是定制 WAF 策略的基础:
# ModSecurity 规则格式
# SecRule VARIABLES OPERATOR [ACTIONS]
# 示例:检测 SQL 注入
SecRule ARGS "@rx (?i)(union[\s/\*]+select|select[\s/\*]+.*from|insert[\s/\*]+into)" \
"id:100001,\
phase:2,\
deny,\
status:403,\
log,\
msg:'SQL Injection Detected',\
severity:'CRITICAL',\
tag:'attack-sqli'"
# 变量(VARIABLES)——检查请求的哪些部分
# ARGS 所有请求参数(GET + POST)
# ARGS_GET GET 参数
# ARGS_POST POST 参数
# REQUEST_URI 请求 URI
# REQUEST_BODY 请求体
# REQUEST_HEADERS 请求头
# REQUEST_COOKIES Cookie
# XML XML 请求体(解析后)
# JSON JSON 请求体(解析后)
# 操作符(OPERATOR)——怎么匹配
# @rx 正则表达式
# @pm 短语匹配(多关键词)
# @pmFromFile 从文件加载关键词列表
# @eq / @gt / @lt 数值比较
# @ipMatch IP 地址/CIDR 匹配
# @contains 包含字符串
# @detectSQLi libinjection SQL 注入检测
# @detectXSS libinjection XSS 检测
# 动作(ACTIONS)——匹配后做什么
# deny 拦截
# pass 放行(用于记录)
# redirect 重定向
# setvar 设置变量(用于异常评分)
# chain 链式规则(AND 条件)
一个完整的自定义规则示例:
# 检测命令注入——匹配请求参数中的 shell 命令字符
SecRule ARGS "@rx (?:;|\||`|\$\()" \
"id:100010,\
phase:2,\
block,\
capture,\
t:none,\
t:urlDecodeUni,\
t:htmlEntityDecode,\
t:compressWhiteSpace,\
log,\
msg:'Command Injection Attempt: %{MATCHED_VAR}',\
logdata:'Matched Data: %{TX.0} in %{MATCHED_VAR_NAME}',\
severity:'CRITICAL',\
tag:'attack-rce',\
tag:'OWASP_CRS',\
setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
# 注意 t: 开头的转换函数——它们在匹配前对输入做归一化处理
# urlDecodeUni: URL 解码(含 Unicode)
# htmlEntityDecode: HTML 实体解码
# compressWhiteSpace: 压缩空白字符
# 这些转换是防 WAF 绕过的关键
三、WAF 绕过与防御
WAF 绕过是安全攻防的核心议题。理解攻击者的绕过手法才能写出有效的规则。
3.1 编码绕过
原始 payload: <script>alert(1)</script>
# URL 编码
%3Cscript%3Ealert(1)%3C%2Fscript%3E
# 双重 URL 编码
%253Cscript%253Ealert(1)%253C%252Fscript%253E
# Unicode 编码
%u003Cscript%u003Ealert(1)%u003C/script%u003E
# HTML 实体编码
<script>alert(1)</script>
# 混合编码
%3Cscr%69pt%3Ealert(1)%3C/scr%69pt%3E
防御:在正则匹配前先做多层解码(归一化):
# ModSecurity 的多层转换
SecRule ARGS "@rx <script>" \
"id:100020,\
phase:2,\
deny,\
t:none,\
t:urlDecodeUni,\ # URL 解码(含 Unicode)
t:htmlEntityDecode,\ # HTML 实体解码
t:jsDecode,\ # JavaScript 解码
t:cssDecode,\ # CSS 解码
t:utf8toUnicode,\ # UTF-8 转 Unicode
t:lowercase,\ # 大小写归一化
t:compressWhiteSpace" # 空白压缩
3.2 SQL 注入绕过
-- 原始 payload
' OR 1=1 --
-- 注释分割
'/**/OR/**/1=1--
-- 大小写混淆
' oR 1=1 --
-- 等价函数替换
' OR ASCII(SUBSTRING(password,1,1))>64 --
-- 无空格
'OR'1'='1'
-- 科学计数法
' OR 1e0=1e0 --
-- 制表符替代空格
' OR\t1=1\t--
-- 多行注释嵌套
'/*!50000OR*/1=1--
-- JSON/XML 载体(WAF 可能不解析 body 格式)
{"query": "' OR 1=1 --"}libinjection 防御:
# CRS 使用 libinjection 的语义分析替代纯正则
# libinjection 将 SQL 片段标记化为 token 序列
# 例如 ' OR 1=1 -- 被标记为 s&1
# 其中 s=string, &=operator, 1=number
# ModSecurity 调用 libinjection
SecRule ARGS "@detectSQLi" \
"id:942100,\
phase:2,\
block,\
t:none,\
t:urlDecodeUni,\
t:removeNulls,\
msg:'SQL Injection Attack Detected via libinjection',\
severity:'CRITICAL'"
libinjection 的优势在于它不依赖正则表达式,而是对 SQL 语法做词法分析——编码和混淆无法改变 token 序列的语义特征。
3.3 XSS 绕过
<!-- 原始 payload -->
<script>alert(1)</script>
<!-- 事件处理器 -->
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<body onpageshow=alert(1)>
<!-- 不使用尖括号 -->
javascript:alert(1)
data:text/html,<script>alert(1)</script>
<!-- 模板注入 -->
{{constructor.constructor('return this')().alert(1)}}
<!-- 利用 DOM API -->
<a href="javascript:void(0)" onclick="this.href='javascript:alert(1)'">
<!-- SVG 内嵌 -->
<svg><script>alert(1)</script></svg>
<!-- 编码混淆 -->
<script>eval(atob('YWxlcnQoMSk='))</script>3.4 协议层绕过
WAF 通常在 HTTP 解析后检查内容。如果 WAF 的 HTTP 解析行为与后端服务器不一致,就产生了绕过空间:
# Request Smuggling — WAF 和后端对 Content-Length 和
# Transfer-Encoding 的解析不一致
# CL.TE 攻击(WAF 看 Content-Length,后端看 Transfer-Encoding)
POST / HTTP/1.1
Host: target.com
Content-Length: 6
Transfer-Encoding: chunked
0
G
# WAF 认为 body 是 "0\r\n\r\nG" (6 字节),放行
# 后端按 chunked 解析,"0\r\n\r\n" 是终止标记
# "G" 被解析为下一个请求的开头
防御措施:
# 拒绝同时携带 Content-Length 和 Transfer-Encoding 的请求
SecRule REQUEST_HEADERS:Transfer-Encoding "." \
"chain,\
id:100030,\
phase:1,\
deny"
SecRule REQUEST_HEADERS:Content-Length "." \
"msg:'Request with both CL and TE headers'"
# 拒绝异常的 Transfer-Encoding 值
SecRule REQUEST_HEADERS:Transfer-Encoding "!@rx ^chunked$" \
"id:100031,\
phase:1,\
deny,\
msg:'Invalid Transfer-Encoding'"
3.5 WAF 绕过防御总结
| 绕过类型 | 攻击手法 | 防御措施 |
|---|---|---|
| 编码绕过 | URL/HTML/Unicode 编码 | 多层归一化(t:urlDecodeUni + t:htmlEntityDecode) |
| 大小写绕过 | SeLeCt、ScRiPt |
小写归一化(t:lowercase) |
| 注释分割 | SEL/**/ECT |
去注释 + 语义分析(libinjection) |
| 空白替换 | Tab、换行替代空格 | 空白压缩(t:compressWhiteSpace) |
| 等价替换 | CHAR(65) 替代 'A' |
语义分析 + 函数黑名单 |
| 协议走私 | CL/TE 不一致 | 拒绝歧义请求 |
| 分块传输 | Chunked 拆分 payload | 完整重组后再检查 |
| 多部分绕过 | multipart/form-data 嵌套 | 完整解析 multipart body |
四、误报控制
误报(False Positive)是 WAF 运维中最大的挑战。CRS 在 Paranoia Level 1 下典型误报率约 1–3%,但对于高流量网站,1% 的误报意味着每天数千个合法请求被拦截。
4.1 误报的常见来源
常见误报场景:
1. 富文本编辑器 — 用户输入包含 HTML 标签
误匹配规则:941xxx (XSS)
2. 搜索查询 — 用户搜索 SQL 关键词
例:"SELECT 语句怎么写"
误匹配规则:942xxx (SQLi)
3. API JSON Body — JSON 值包含特殊字符
例:{"code": "if (x > 0) { return; }"}
误匹配规则:941xxx (XSS), 932xxx (RCE)
4. 长 URL / 大 Cookie — 正常业务但超出 WAF 默认限制
误匹配规则:920xxx (Protocol)
5. 文件上传 — 上传内容包含可执行代码
误匹配规则:930xxx (LFI), 932xxx (RCE)
4.2 规则排除策略
ModSecurity 提供三种规则排除方式:
# 方式 1:完全移除规则(简单但粗暴)
# 不推荐:移除整条规则意味着对所有请求都不检查
SecRuleRemoveById 942100
# 方式 2:按 URI 排除(推荐)
# 只对特定路径排除特定规则
SecRule REQUEST_URI "@beginsWith /api/editor" \
"id:100040,\
phase:1,\
pass,\
ctl:ruleRemoveTargetById=941100;ARGS:content,\
ctl:ruleRemoveTargetById=941160;ARGS:content"
# 只对 /api/editor 端点的 content 参数排除 XSS 规则
# 其他端点和其他参数仍然受保护
# 方式 3:按参数排除(精确)
# 对特定参数排除特定规则,不限 URI
SecRuleUpdateTargetById 942100 "!ARGS:search_query"
# 所有请求的 search_query 参数不触发 SQL 注入规则 942100
4.3 渐进式部署流程
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 阶段 1 │ │ 阶段 2 │ │ 阶段 3 │
│ Detection │ ──→ │ Tuning │ ──→ │ Blocking │
│ Only │ │ │ │ │
│ │ │ │ │ │
│ • 只记录 │ │ • 分析日志 │ │ • 开启拦截 │
│ • 不拦截 │ │ • 排除误报 │ │ • 持续监控 │
│ • 收集数据 │ │ • 调整阈值 │ │ • 迭代优化 │
│ │ │ │ │ │
│ 时间:2-4周 │ │ 时间:2-4周 │ │ 持续运维 │
└──────────────┘ └──────────────┘ └──────────────┘
阶段 1:检测模式(Detection Only)
# ModSecurity 检测模式配置
SecRuleEngine DetectionOnly
# 所有规则只记录,不拦截
# 审计日志记录所有触发规则的请求
SecAuditEngine RelevantOnly
SecAuditLogParts ABCDEFHZ
SecAuditLog /var/log/modsec_audit.log
SecAuditLogType Serial
阶段 2:日志分析与误报排除
# 分析 ModSecurity 审计日志
# 统计触发最多的规则 ID
grep -oP 'id "\K\d+' /var/log/modsec_audit.log | \
sort | uniq -c | sort -rn | head -20
# 统计被标记的 URI
grep -oP 'REQUEST_URI.*' /var/log/modsec_audit.log | \
sort | uniq -c | sort -rn | head -20
# 查看特定规则的触发详情
grep -A 5 'id "942100"' /var/log/modsec_audit.log | head -50阶段 3:逐步开启拦截
# 先用高阈值,逐步降低
# 第一周:阈值 20(只拦截明确攻击)
SecAction "id:900110,phase:1,pass,\
setvar:tx.inbound_anomaly_score_threshold=20"
# 第二周:阈值 10
# 第三周:阈值 5(CRS 推荐值)
# 切换到拦截模式
SecRuleEngine On
4.4 误报率的量化监控
# Prometheus 指标设计
# prometheus-waf-metrics.yml
groups:
- name: waf_metrics
rules:
# WAF 拦截率
- record: waf:block_rate:5m
expr: |
rate(waf_requests_blocked_total[5m])
/ rate(waf_requests_total[5m])
# 误报率(需要人工标注或自动验证)
- alert: WAFHighBlockRate
expr: waf:block_rate:5m > 0.05
for: 10m
labels:
severity: warning
annotations:
summary: "WAF 拦截率超过 5%,可能存在误报问题"五、正则 WAF vs 语义分析 WAF
5.1 正则 WAF 的局限
正则 WAF(如传统 ModSecurity + CRS)的核心问题:
- 正则灾难:复杂正则可能导致 ReDoS(正则拒绝服务),恶意构造的输入让正则引擎陷入指数级回溯
- 维护成本:规则库需要不断更新以应对新绕过手法
- 上下文缺失:正则不理解语法语义,只做字符串模式匹配
# ReDoS 示例
# 以下正则在处理特定输入时可能导致指数级回溯
# 正则: (a+)+$
# 输入: aaaaaaaaaaaaaaaaaaaX
# 回溯次数随 a 的数量指数增长
# ModSecurity 的缓解措施
# 设置正则匹配的时间限制
SecPcreMatchLimit 500000
SecPcreMatchLimitRecursion 500000
5.2 语义分析 WAF
语义分析 WAF 不使用正则,而是对输入做词法/语法分析,理解其”意图”:
传统正则 WAF:
输入: "1' OR '1'='1"
匹配: /OR\s+'.*'='.*'/i → 命中
绕过: "1' || '1'like'1" → 可能不命中
语义分析 WAF:
输入: "1' OR '1'='1"
→ SQL 词法分析
→ Token: [NUMBER, QUOTE, OR, QUOTE, NUMBER, QUOTE, EQUALS,
QUOTE, NUMBER, QUOTE]
→ 语义判断:这是一个永真条件注入 → 拦截
输入: "1' || '1'like'1"
→ SQL 词法分析
→ Token: [NUMBER, QUOTE, PIPE_PIPE, QUOTE, NUMBER, QUOTE,
LIKE, QUOTE, NUMBER, QUOTE]
→ 语义判断:等价永真条件 → 拦截
libinjection 是 SQL 注入语义分析的代表:
libinjection 的 fingerprint 机制:
将 SQL 片段标记化为简短的 token 序列
输入 fingerprint
"1 OR 1=1" → "1o1" (number-or-number)
"admin'--" → "s1c" (string-number-comment)
"' UNION SELECT" → "sUE" (string-union-expression)
"1' AND 1=CONVERT(int,@@version)" → "s&1f" (复杂注入)
已知恶意 fingerprint 库 → 匹配即拦截
5.3 对比
| 维度 | 正则 WAF | 语义分析 WAF |
|---|---|---|
| 检测准确率 | 高(规则好的话) | 更高(理解语义) |
| 绕过难度 | 中等(编码/混淆可绕过) | 高(需要构造语义等价变换) |
| 性能 | 正则数量多时 CPU 高 | 词法分析通常更快 |
| 维护成本 | 需要持续更新规则 | 语法变化时需更新解析器 |
| 误报率 | 中等 | 低 |
| 覆盖范围 | 广(任意模式) | 窄(只覆盖已实现的语言) |
| ReDoS 风险 | 有 | 无 |
| 代表产品 | ModSecurity + CRS | libinjection, Coraza |
实际生产中,最佳实践是组合使用:先用语义分析检测已知注入类型(SQLi、XSS),再用正则规则覆盖语义分析未覆盖的攻击类型(LFI、RCE 等)。
六、Nginx + ModSecurity 部署实战
6.1 安装与配置
# Ubuntu 22.04 安装 ModSecurity v3 + Nginx connector
apt-get install -y libmodsecurity3 libmodsecurity-dev
apt-get install -y nginx libnginx-mod-http-modsecurity
# 或从源码编译(获取最新版本)
# git clone https://github.com/SpiderLabs/ModSecurity.git
# cd ModSecurity && git checkout v3/master
# git submodule init && git submodule update
# ./build.sh && ./configure && make && make installNginx 集成配置:
# /etc/nginx/nginx.conf 或 sites-available/default
server {
listen 443 ssl http2;
server_name example.com;
# 启用 ModSecurity
modsecurity on;
modsecurity_rules_file /etc/nginx/modsecurity/main.conf;
location / {
proxy_pass http://backend;
}
}
# /etc/nginx/modsecurity/main.conf
Include /etc/nginx/modsecurity/modsecurity.conf
Include /etc/nginx/modsecurity/crs/crs-setup.conf
Include /etc/nginx/modsecurity/crs/rules/*.conf
# 自定义规则(在 CRS 之后加载)
Include /etc/nginx/modsecurity/custom-rules/*.conf
# 白名单规则(在自定义规则之后加载)
Include /etc/nginx/modsecurity/whitelist/*.conf
6.2 CRS 配置优化
# /etc/nginx/modsecurity/crs/crs-setup.conf 关键配置
# 偏执级别(推荐从 1 开始)
SecAction "id:900000,phase:1,pass,\
setvar:tx.paranoia_level=1,\
setvar:tx.executing_paranoia_level=1"
# 异常评分阈值
SecAction "id:900110,phase:1,pass,\
setvar:tx.inbound_anomaly_score_threshold=5,\
setvar:tx.outbound_anomaly_score_threshold=4"
# 允许的 HTTP 方法
SecAction "id:900200,phase:1,pass,\
setvar:'tx.allowed_methods=GET HEAD POST PUT DELETE OPTIONS PATCH'"
# 允许的 Content-Type
SecAction "id:900220,phase:1,pass,\
setvar:'tx.allowed_request_content_type=\
|application/x-www-form-urlencoded|\
|multipart/form-data|\
|multipart/related|\
|text/xml|\
|application/xml|\
|application/soap+xml|\
|application/json|\
|application/grpc|'"
# 响应体检查(建议关闭以提高性能)
SecResponseBodyAccess Off
6.3 性能调优
# ModSecurity 性能配置
# /etc/nginx/modsecurity/modsecurity.conf
# 请求体检查上限(大于此值不检查 body)
SecRequestBodyLimit 13107200
SecRequestBodyNoFilesLimit 131072
# PCRE 正则匹配限制(防 ReDoS)
SecPcreMatchLimit 500000
SecPcreMatchLimitRecursion 500000
# 审计日志只记录被标记的请求
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
# 使用 JSON 格式日志便于分析
SecAuditLogFormat JSON
SecAuditLogType Serial
SecAuditLog /var/log/modsec/audit.json
# 临时文件目录
SecTmpDir /tmp/modsecurity
SecDataDir /tmp/modsecurity_data
性能基准参考:
| 配置 | 延迟增加 | 吞吐量下降 |
|---|---|---|
| CRS PL1,小请求 | <1ms | <5% |
| CRS PL2,中请求 | 1–3ms | 5–10% |
| CRS PL3,大请求 | 3–10ms | 10–20% |
| CRS PL4,大请求 | 10–50ms | 20–50% |
| 无 body 检查 | <0.5ms | <3% |
七、WAF 运维最佳实践
7.1 日志分析与安全运营
# 分析 WAF JSON 审计日志
# 统计攻击类型分布
cat /var/log/modsec/audit.json | \
python3 -c "
import sys, json
from collections import Counter
tags = Counter()
for line in sys.stdin:
try:
entry = json.loads(line)
for msg in entry.get('transaction', {}).get('messages', []):
for tag in msg.get('details', {}).get('tags', []):
if tag.startswith('attack-'):
tags[tag] += 1
except: pass
for tag, count in tags.most_common(20):
print(f'{count:>6} {tag}')
"
# 统计被拦截的源 IP
cat /var/log/modsec/audit.json | \
python3 -c "
import sys, json
from collections import Counter
ips = Counter()
for line in sys.stdin:
try:
entry = json.loads(line)
tx = entry.get('transaction', {})
if tx.get('response', {}).get('http_code', 0) == 403:
ips[tx.get('client_ip', 'unknown')] += 1
except: pass
for ip, count in ips.most_common(20):
print(f'{count:>6} {ip}')
"7.2 WAF 测试
WAF 部署后需要定期测试其有效性。常用的测试工具和方法:
# 使用 nikto 进行基础 WAF 测试
nikto -h https://example.com -Tuning 9
# 使用 wfuzz 进行规则覆盖测试
# 测试 SQL 注入规则
wfuzz -z file,/usr/share/wordlists/sqli.txt \
-d "id=FUZZ" --hc 200 \
https://example.com/api/user
# 手动测试常见攻击向量
# SQL 注入
curl -s -o /dev/null -w "%{http_code}" \
"https://example.com/search?q=1'+OR+1=1--"
# 期望:403
# XSS
curl -s -o /dev/null -w "%{http_code}" \
"https://example.com/search?q=<script>alert(1)</script>"
# 期望:403
# 命令注入
curl -s -o /dev/null -w "%{http_code}" \
-d "cmd=;cat /etc/passwd" \
https://example.com/api/exec
# 期望:403
# 路径遍历
curl -s -o /dev/null -w "%{http_code}" \
"https://example.com/file?path=../../../etc/passwd"
# 期望:4037.3 WAF 选型对比
| 产品 | 类型 | 规则引擎 | 语义分析 | 部署方式 | 成本 |
|---|---|---|---|---|---|
| ModSecurity 3 | 开源 | 正则 + libinjection | 部分 | 嵌入 Nginx/Apache | 免费 |
| Coraza | 开源 | 兼容 ModSecurity | 是 | 嵌入/Sidecar | 免费 |
| Cloudflare WAF | 云服务 | 正则 + ML | 是 | 云端 | $20+/月 |
| AWS WAF | 云服务 | 正则 + Bot Control | 部分 | AWS 生态 | 按规则计费 |
| F5 ASM | 商业 | 正则 + 正向模型 | 是 | 硬件/虚拟 | 高 |
| Imperva | 商业 | 正则 + ML | 是 | 云端/本地 | 高 |
选型建议: - 已使用 CDN → 优先使用 CDN 自带 WAF(一体化管理) - 云原生架构 → 云 WAF(AWS WAF / GCP Cloud Armor) - 需要深度定制 → ModSecurity 或 Coraza(开源可控) - Service Mesh 环境 → Coraza 作为 Envoy Filter
参考文献
- OWASP Foundation, “OWASP ModSecurity Core Rule Set,” github.com/coreruleset/coreruleset.
- Trustwave, “ModSecurity Reference Manual,” github.com/SpiderLabs/ModSecurity.
- Gallagher, N., “libinjection: A C Library for SQL/XSS Injection Detection,” github.com/libinjection.
- OWASP Foundation, “OWASP Top 10 Web Application Security Risks,” owasp.org.
- Ristic, I., “ModSecurity Handbook,” Feisty Duck, 2nd Edition.
- Coraza WAF, “Coraza: Enterprise-Grade Web Application Firewall,” github.com/corazawaf/coraza.
- Cloudflare, “WAF Attack Score and WAF ML,” Cloudflare Documentation.
- PortSwigger, “Web Security Academy: WAF Bypass Techniques,” portswigger.net.
上一篇: DDoS 防御架构:容量型、协议型与应用层攻击 下一篇: 网络入侵检测与防御:Suricata、签名与异常检测
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【网络工程】QUIC 生态与工程部署:从实验到生产
QUIC 已经不是实验性协议——HTTP/3 标准化后,CDN、浏览器和主流服务端框架都在推进 QUIC 支持。本文从工程视角对比主流 QUIC 库的成熟度和性能特征,讲解 CDN/负载均衡器的 QUIC 适配方案、从 TCP 迁移到 QUIC 的渐进路径、QUIC 调试工具链,以及生产环境的部署陷阱和性能调优实践。
【网络工程】eBPF 可编程网络:从包过滤到流量工程
eBPF 正在重新定义网络工程——从传统的 iptables/netfilter 规则堆砌,到可编程、可观测、高性能的网络数据平面。本文系统讲解 eBPF 网络程序类型(XDP/TC/Socket)、Map 数据结构、Cilium 的 eBPF 数据平面实现,以及 eBPF 在负载均衡、可观测性和网络安全中的工程实践。
【网络工程】可编程数据平面与 P4:软件定义转发
传统网络设备的转发逻辑固化在硬件中。P4 语言让交换机的转发管线可编程——你可以定义自己的包头解析、匹配规则和转发动作。本文从 P4 语言核心概念出发,讲解 Parser/Match-Action/Deparser 的编程模型、可编程交换机芯片(Tofino)的架构、P4 在数据中心和运营商网络中的应用案例,以及 P4 与 eBPF 的定位差异。
【网络工程】网络模拟与测试:netem、Mininet 与混沌工程
生产环境的网络条件远比实验室复杂——延迟抖动、随机丢包、带宽突变、链路故障。本文系统讲解 tc netem 的完整用法、Mininet 虚拟网络拓扑搭建、网络层混沌工程(Toxiproxy/Comcast/tc-netem)的实战方法,以及如何在 CI/CD 流水线中集成网络条件测试,确保应用在恶劣网络下的鲁棒性。