土法炼钢兴趣小组的算法知识备份

【网络工程】WAF 工程:规则设计、误报控制与绕过防御

文章导航

分类入口
network
标签入口
#waf#modsecurity#owasp-crs#web-security#application-firewall

目录

上一篇讲了 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 实体编码
&#60;script&#62;alert(1)&#60;/script&#62;

# 混合编码
%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)的核心问题:

  1. 正则灾难:复杂正则可能导致 ReDoS(正则拒绝服务),恶意构造的输入让正则引擎陷入指数级回溯
  2. 维护成本:规则库需要不断更新以应对新绕过手法
  3. 上下文缺失:正则不理解语法语义,只做字符串模式匹配
# 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 install

Nginx 集成配置:

# /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"
# 期望:403

7.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

参考文献

  1. OWASP Foundation, “OWASP ModSecurity Core Rule Set,” github.com/coreruleset/coreruleset.
  2. Trustwave, “ModSecurity Reference Manual,” github.com/SpiderLabs/ModSecurity.
  3. Gallagher, N., “libinjection: A C Library for SQL/XSS Injection Detection,” github.com/libinjection.
  4. OWASP Foundation, “OWASP Top 10 Web Application Security Risks,” owasp.org.
  5. Ristic, I., “ModSecurity Handbook,” Feisty Duck, 2nd Edition.
  6. Coraza WAF, “Coraza: Enterprise-Grade Web Application Firewall,” github.com/corazawaf/coraza.
  7. Cloudflare, “WAF Attack Score and WAF ML,” Cloudflare Documentation.
  8. PortSwigger, “Web Security Academy: WAF Bypass Techniques,” portswigger.net.

上一篇: DDoS 防御架构:容量型、协议型与应用层攻击 下一篇: 网络入侵检测与防御:Suricata、签名与异常检测

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-06-29 · linux / network

【rsync 原理】差异同步算法:滚动校验与两级匹配

源端看不到目标端文件,rsync 凭什么只传改动的几 KB?从 Tridgell 的 rsync 算法出发,用 rsync 3.4.4 源码钉住弱滚动校验的 O(1) 更新、弱+强两级匹配、sqrt 块大小与签名长度随文件增长的权衡,讲清差异是怎么在不传整文件的前提下被算出来的。

2026-06-29 · linux / network

【rsync 原理】协议、进程模型与实测

rsync 的差异算法落到真实工具里,是 generator/sender/receiver 三个进程在一条管线上跑。本文用 rsync 3.4.4 源码与 wire 行为讲清三角色分工、文件列表与逐文件生命周期、token 字节流格式、强校验协商与版本边界,并在本机内核 6.6 上实测:100 MiB 文件改 1 字节,delta 走约 120 KB,whole-file 走整 100 MiB。

2026-06-20 · network

【网络工程】WireGuard 内部实现:Cryptokey Routing、Noise IK 握手与内核数据路径

WireGuard 用不到 4000 行内核代码替代了 IPSec/IKE 数十万行的协议栈——这不是少写功能,而是用固定密码学原语、固定握手模式和 cryptokey routing 这三个设计决定,换掉了证书体系、协商机和 SPD/SAD 分离。本文钻进源码和协议握手过程,逐层拆解 cryptokey routing 的双向执行、Noise IKpsk2 的 1.5 RTT 握手(含四次 ECDH 的安全属性贡献)、内核多核队列架构、timer 状态机、cookie DoS 防御和三密钥对轮换。

2026-04-22 · network

网络工程索引

汇总本站网络工程系列文章,覆盖分层模型、以太网、IP、TCP、DNS、TLS、HTTP/2/3、CDN、BGP 与故障诊断。


By .