4. Suricata规则语法入门
Suricata 的检测能力几乎全部建立在规则之上。一条规则既是“匹配条件”,也是“告警说明”,还决定了流量命中后要执行什么动作。理解规则语法,是后续编写自定义规则、调试误报漏报、以及把机器学习检测结果落地为可运营规则的前提。Suricata 规则整体上可以拆成两大部分:规则头部(Rule Header)和规则选项(Rule Options)。头部负责“对什么流量、从哪到哪、做什么动作”,选项负责“满足什么条件才算命中、命中后输出什么信息”。
action protocol src_ip src_port -> dst_ip dst_port (option1; option2; ...; sid:1000001; rev:1;)头部与选项之间用空格分隔,选项整体放在一对圆括号内,每个选项以分号结尾。
一、规则头部:动作、协议、地址端口与方向
规则头部由六个字段组成,顺序固定,不能随意调换。第一个字段是动作(action),常见取值有 alert、drop、pass、reject。在 IDS 模式下通常使用 alert,只记录告警;在 IPS 模式下 drop 会直接丢弃报文,reject 还会返回拒绝响应。第二个字段是协议(protocol),可以是 tcp、udp、icmp、ip、http、dns、tls 等。注意 http、dns 这类属于应用层协议关键字,Suricata 会结合端口和协议解析结果进行匹配。
第三、四个字段是源地址与源端口,第五、六个字段是目的地址与目的端口,中间用方向符号连接。方向符号有两种:-> 表示单向,即从左向右匹配;<> 表示双向,两个方向都会匹配。地址可以写具体 IP、CIDR 网段、变量(如 $HOME_NET、$EXTERNAL_NET),也可以用 any 表示任意地址。端口可以写具体端口、端口范围(如 1024: 表示 1024 及以上)、端口列表(如 [80,443,8080]),同样支持 any。
二、规则选项:匹配条件与元信息
选项是规则真正“做判断”的地方。它由若干键值对组成,每个以分号结尾。可以把它分成四类:内容匹配类(content、pcre、dsize)、流与状态类(flow、flags、threshold)、协议字段类(http_uri、http_header、tls_sni、dns_query)、元信息与输出类(msg、sid、rev、classtype、reference)。其中 sid 是规则唯一编号,rev 是版本号,二者是规则可管理、可升级的基础。
需要特别理解 flow 选项,它决定规则在连接的哪个阶段生效。例如 flow:to_server,established 表示只匹配已建立连接中客户端发往服务端的流量,常用于 HTTP 请求检测;flow:to_client,established 则用于响应方向检测。若忽略 flow,规则可能在握手包或重传包上误命中,造成大量噪声。
三、案例:一条 HTTP 检测规则的完整拆解
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"Possible SQL Injection in HTTP URI";
flow:to_server,established;
http.uri;
content:"union"; nocase;
content:"select"; nocase; distance:0;
classtype:web-application-attack;
sid:1000001; rev:1;
)
逐段解读:alert 表示只告警;http 表示由 HTTP 解析器处理;$HOME_NET any -> $EXTERNAL_NET any 表示内网到外网的任意端口流量;flow:to_server,established 限定请求方向且连接已建立;http.uri 把后续 content 的匹配范围限定在 URI 字段;两个 content 配合 distance:0 表示“union”和“select”需在 URI 中相邻出现;classtype 用于分类;sid 与 rev 用于版本管理。这样一条规则就具备了明确的匹配边界和可运营的元信息。
四、常见误区与复盘清单
| 误区 | 后果 | 正确做法 |
|---|---|---|
| 方向符号写反 | 规则永不命中或命中错误方向 | 先确认检测的是请求还是响应,再选 -> 或 <> |
缺少 flow 选项 | 握手、重传包触发大量误报 | 按场景补充 flow:to_server,established 等 |
content 未限定字段 | 在整包任意位置匹配,噪声高 | 配合 http.uri、http.header 等缩小范围 |
sid 重复或缺失 | 规则加载失败或无法追踪 | 本地规则使用独立号段,如 1000000 起 |
忽略 rev 递增 | 规则更新后无法区分版本 | 每次修改规则同步递增 rev |
msg、sid、rev。这样写出的规则结构清晰,也便于后续用 suricata -T 做语法校验。