重写慢规则并对比优化前后吞吐

约 35 分钟

能根据性能统计重写慢规则,并通过回放对比优化前后的检查次数与耗时。

上一课结束时,profiling 报告已经给出了结论:哪些规则检查次数高、耗时高,我们又用“总开销 × 产出价值”圈定了最该优化的慢规则。定位完成,这节课动手改它。

流程只有三步:记录基线,重写规则,重跑对比。三次回放同一个 PCAP,环境不变,变的只有规则本身。

回放继续用离线模式,Suricata 用 -r 参数读取 PCAP,操作方式与上一课一致。跑完后,用 fast.log 确认告警是否出现,确保改动没有影响规则原本的检出能力。

练习数据用本地 PCAP 或公开教学包。整个过程只做检测与对比,不做攻击性操作。

核心概念

慢规则重写:从命中面到检查次数

类比:在一整本词典里找单词,只能逐页翻;先知道首字母和大概页数,翻找范围立刻缩小。规则的 content 是你要找的"单词",修饰符是"页数与行号"。

定义:profiling 报告里,每条规则都有检查次数与平均耗时。检查次数高,说明这条规则的 content 在流量里频繁命中,Suricata 为它付出大量工作。重写只有两个方向:让 content 更具体,或用修饰符收紧搜索范围。content 越具体、修饰符约束越紧,命中面越小,检查次数与耗时越低。改完必须重跑 profiling 验证数字,并在同一 PCAP 上确认告警仍然命中。只降数字、丢了告警,等于把规则改废了。

记录优化前的基线

  1. 1

    确认宽泛版规则已存在。这条规则在任何 IP 载荷里搜索 uid=0,命中面很大:

    shell
    alert ip any any -> any any (msg:"Root response possible"; content:"uid=0"; nocase; sid:5000001; rev:1;)
  2. 2

    开启规则性能统计。suricata.yaml 位于 /etc/suricata/suricata.yaml,按上一课的方式在配置里启用 profiling:

    shell
    sudo vim /etc/suricata/suricata.yaml
  3. 3

    回放同一个 PCAP,让统计覆盖完整流量。把 path-to-pcap 换成你的文件:

    shell
    sudo suricata -r /path/to/training.pcap
  4. 4

    从 profiling 输出中找出 sid 5000001,记录它的检查次数与平均耗时,作为基线。

  5. 5

    确认这条规则当前能告警。打开 fast.log 搜索该 sid:

    shell
    grep 5000001 /var/log/suricata/fast.log

你应该看到

你手里有基线数据:sid 5000001 的检查次数与平均耗时,以及 fast.log 中对应的一条告警记录。

用更具体的内容与修饰符重写

  1. 1

    看基线的检查次数,找出宽在哪里。sid 5000001 只在任意 IP 载荷里找 uid=0,无关流量也会频繁命中。

  2. 2

    把 content 换成更具体的字节串。参考成熟规则对同一现象的写法,|28| 与 |29| 是括号字符的十六进制转义。写成你自己的新规则:

    shell
    alert ip any any -> any any (msg:"ATTACK_RESPONSE id check returned root"; content:"uid=0|28|root|29|"; classtype:bad-unknown; sid:5000002; rev:2;)
  3. 3

    如果目标串出现在固定位置,用 offset 与 depth 限制搜索起点与终点;如果目标由两段组成,用 distance 与 within 约束两段之间的相对位置。修饰符不改变匹配内容,只缩小搜索范围。

  4. 4

    用测试模式(-T,见第 1 章实验)验证新规则语法,确认没有报错。

  5. 5

    保存规则文件,路径要与 suricata.yaml 中配置的位置一致。

你应该看到

新规则 sid 5000002 语法校验通过,content 比基线更具体,命中面更小。

重写的顺序有讲究。先改 content:把一个常见词换成一串更完整的字节。再加修饰符:offset、depth、distance、within 只缩小搜索范围,不改变匹配内容。最后才考虑 pcre——content 和修饰符表达不了的模式才交给正则。

每改一步都值得重跑一次 profiling,看数字是否真的下降。改完一处、立刻验证,比一次改完再回头找原因快得多。

对比是这次实验的核心动作。两轮数字要并排看:

| 轮次 | sid | 检查次数 | 平均耗时 | fast.log 命中 | | 基线 | 5000001 | 128400(示例) | 高 | 有 | | 优化后 | 5000002 | 320(示例) | 低 | 有 |

数字下降的原因:命中面变小。uid=0 让每个 IP 载荷都有机会匹配;uid=0|28|root|29| 只有在完整出现这段字节时才匹配。

判断标准有两条,缺一不可:检查次数或平均耗时下降;同一 PCAP 回放仍能在 fast.log 看到告警。

示例数字来自教学场景,你的环境会得到不同的具体值。

重跑 profiling 并验证告警

  1. 1

    用与基线完全相同的命令,回放同一个 PCAP:

    shell
    sudo suricata -r /path/to/training.pcap
  2. 2

    从新的 profiling 输出中找到 sid 5000002,记录检查次数与平均耗时。

  3. 3

    确认告警仍然命中,搜索新 sid:

    shell
    grep 5000002 /var/log/suricata/fast.log
  4. 4

    把两轮数字写进实验记录:sid、检查次数、平均耗时、是否命中,逐项对比。

你应该看到

sid 5000002 的检查次数或平均耗时低于基线 sid 5000001,且 fast.log 中仍能看到对应告警。若数字下降但告警消失,进入故障排查。

遇到问题:优化后 fast.log 里找不到新规则 sid 5000002 的告警。

可能原因

  • 新规则的 content 写得太具体,与 PCAP 中目标流量的实际字节不一致。
  • 新规则没有被加载:规则文件路径与 suricata.yaml 配置不一致,或语法错误被跳过。
  • 告警被 threshold 或 suppress 配置抑制。

排查步骤

  1. 用 Wireshark 打开同一个 PCAP,先看协议层次,再跟随 TCP 流,把 content 对准流量里的真实字节后重写。
  2. 用测试模式再次验证语法,并从 Suricata 日志里核对规则文件路径。
  3. 检查规则文件里是否存在针对该 sid 的 threshold 或 suppress。

遇到问题:重写并重跑后,检查次数几乎没有下降。

可能原因

  • 新 content 在流量里仍然很常见,命中面没有实质缩小。
  • 两次回放用的不是同一个 PCAP,或命令行参数不一致,基线不可比。

排查步骤

  1. 回到 Wireshark 看目标流量的上下文,用更长的字节串,或增加 offset、depth、distance、within 收紧范围。
  2. 把两次回放固定为同一个 PCAP 与同一组参数,重新记录基线再对比。
自检:profiling 报告显示某条规则检查次数最高。重写它之后,必须对比哪两个指标?为什么必须用同一个 PCAP 回放并确认告警仍然命中?

对比检查次数与平均耗时。用同一个 PCAP 是为了保证对比条件一致,变化的只有规则本身。确认告警仍然命中,是为了防止把规则改得过严造成漏报。数字下降而告警消失,说明这次优化失败了。