4. Suricata规则语法入门

Suricata 的检测能力几乎全部建立在规则之上。一条规则既是“匹配条件”,也是“告警说明”,还决定了流量命中后要执行什么动作。理解规则语法,是后续编写自定义规则、调试误报漏报、以及把机器学习检测结果落地为可运营规则的前提。Suricata 规则整体上可以拆成两大部分:规则头部(Rule Header)和规则选项(Rule Options)。头部负责“对什么流量、从哪到哪、做什么动作”,选项负责“满足什么条件才算命中、命中后输出什么信息”。

一条 Suricata 规则的通用骨架:
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。

Suricata 规则结构:头部(匹配范围) + 选项(匹配条件与输出) 规则头部 Rule Header action alert / drop protocol tcp / udp / http src_ip src_port $HOME_NET any 方向 -> 或 <> dst_ip dst_port $EXTERNAL_NET 80 ( options ... ) 括号内为规则选项 规则选项 Rule Options(分号分隔,括号包裹) 内容匹配类 content / pcre uricontent / dsize 流与状态类 flow / flags threshold / detection_filter 协议字段类 http_uri / http_header tls_sni / dns_query 元信息与输出类 msg / sid / rev / classtype reference / metadata 匹配顺序:头部先限定协议与地址端口范围 → 选项逐条判断 → 全部满足才触发 action → 输出 msg 与 sid 等元信息 关键约束:sid 必须唯一,rev 随规则修改递增,msg 用于告警可读性,classtype 用于分类统计

二、规则选项:匹配条件与元信息

选项是规则真正“做判断”的地方。它由若干键值对组成,每个以分号结尾。可以把它分成四类:内容匹配类(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 做语法校验。
规则头部字段顺序固定,不能把源端口写到目的地址之后;选项必须整体放在圆括号内,且每个选项以分号结尾。少一个分号或括号,都会导致规则加载失败。上线前务必执行配置测试,确认规则被正确解析。