适用场景
企业内网或云上服务器需要在不改造业务的前提下,实时监测网络流量中的入侵行为:扫描探测、SQL 注入、暴力破解、恶意软件通信等。Suricata 作为开源 IDS/IPS 引擎,支持多线程、协议解析和自定义规则,适合部署在网关旁路(镜像口)或服务器入口,输出告警供安全团队响应。本文从零讲解 Suricata 规则语法与编写实战,帮助你独立编写可用的入侵检测规则。
前置条件
- Linux 服务器(Ubuntu/Debian 或 CentOS),2 核 4G 内存以上
- 已安装 Suricata(本文以 6.x/7.x 为例):
sudo apt install suricata(Ubuntu 22.04+) - 能访问互联网(规则更新需要),了解 TCP/IP 与 HTTP 基础
原理说明
Suricata 规则(Signature)描述「匹配什么流量、触发什么动作」。一条规则由三部分组成:动作 + 头部 + 选项,例如:
alert tcp $HOME_NET any -> $EXTERNAL_NET any \
(msg:"示例规则"; content:"test"; sid:1000001; rev:1;)
其中 alert 是动作(告警/丢弃/拒绝),tcp $HOME_NET any -> $EXTERNAL_NET any 是头部(协议、源、目的),括号内是选项:content 做内容匹配、msg 是告警消息、sid 是唯一规则编号(自定义规则建议从 1000000 起,避免与官方规则冲突)、rev 是版本号。Suricata 还内置了针对 HTTP、DNS、TLS 等协议的应用层关键字(如 http.uri、dns.query),比单纯抓包字节匹配更精准。
操作步骤
1. 确认安装与版本
suricata --build-info | head -n 5
sudo suricata --list-keywords > /dev/null 2>&1; echo "keyword list ok"
2. 创建本地规则文件
sudo mkdir -p /etc/suricata/rules
sudo nano /etc/suricata/rules/local.rules
3. 编写三类典型规则
规则一:检测 HTTP 请求中的 SQL 注入特征(union select / 常见注入函数):
alert http $EXTERNAL_NET any -> $HOME_NET any \
(msg:"ET LOCAL SQLi - union select in URI"; \
flow:established,to_server; \
http.uri; content:"union"; nocase; \
http.uri; content:"select"; nocase; distance:1; \
classtype:attempted-recon; sid:1000001; rev:1;)
规则要求 URI 中同时出现 union 和 select(忽略大小写、间距在 1 字节内),有效降低误报。
规则二:检测 SSH 暴力破解特征(短时间内多次认证失败的典型流量难以单包判定,这里检测畸形 SSH 版本串):
alert tcp $EXTERNAL_NET any -> $HOME_NET 22 \
(msg:"ET LOCAL SSH - abnormal version string"; \
flow:established,to_server; \
content:"SSH-"; offset:0; \
content:"!"; \
classtype:attempted-admin; sid:1000002; rev:1;)
规则三:检测常见后门/恶意软件通信域名(DNS 查询命中黑名单域名):
alert dns $HOME_NET any -> any any \
(msg:"ET LOCAL Malware - known C2 domain query"; \
dns.query; content:"malware-c2.example.com"; nocase; \
classtype:trojan-activity; sid:1000003; rev:1;)
更实用的做法是把 C2 域名列表放在 suricata-update 管理的规则集中,或使用 dns.query; content:!; 配合文件规则(--rule 之外可配置 datasets),本文保持单规则写法便于理解。
4. 在配置中启用本地规则
sudo nano /etc/suricata/suricata.yaml
在 rules-files: 一节追加:
rules-files:
- suricata.rules
- local.rules
5. 校验规则语法并启动
# 语法与配置校验(-T 测试模式)
sudo suricata -T -c /etc/suricata/suricata.yaml \
-S /etc/suricata/rules/local.rules
# 正式启动(systemd)
sudo systemctl enable --now suricata
# 查看运行状态
sudo journalctl -u suricata -n 20 --no-pager
注意:监听流量需抓包权限,默认使用 af-packet 或 pcap 模式,按 /etc/suricata/suricata.yaml 中的网卡配置(af-packet.interface)修改为实际网卡名。
6. 用回放流量触发规则验证
# 手动触发一次 SQL 注入特征请求
curl -s "http://example.com/index.php?id=1%20union%20select%201" > /dev/null
# 查看告警(JSON 日志)
sudo tail -n 5 /var/log/suricata/eve.json | jq -r \
'select(.alert) | .timestamp, .alert.signature, .alert.signature_id'
预期输出包含 ET LOCAL SQLi - union select in URI 与 sid 1000001。
配置验证
# 规则集统计(确认 local.rules 已加载)
sudo suricata -c /etc/suricata/suricata.yaml -T 2>&1 | grep -i "local"
# 应出现 local.rules 相关行,无语法错误
# 查看已加载规则数
sudo suricata --dump-rule-counts -c /etc/suricata/suricata.yaml 2>/dev/null | head
常见问题
FAQ 1:sid 冲突或重复怎么办?
规则编号全局唯一,冲突会导致规则加载失败。官方规则库使用 1-1000000 区间,自定义规则请使用 1000000 以上的编号;多条规则可在 suricata-update list-sources / 规则文件头部用 # sid 说明 注释管理。若启动日志提示 duplicate sid,定位到对应文件删除重复项后重新加载。
FAQ 2:告警太多(误报高)怎么收敛?
按以下顺序收敛:① 收紧匹配条件——组合多个 content 并配合 nocase、distance、within 限定位置;② 限定协议上下文(如只在 http.uri 而非全文匹配);③ 使用 threshold 选项做时间窗口计数(如 60 秒内同 sid 超过 5 次才告警);④ 在 eve.json 接入 SIEM 后按源 IP 聚合分析,将高置信告警升级,其余降级为观察。
总结
本文从 Suricata 规则的三段式结构出发,编写了 SQL 注入、SSH 异常与恶意域名三类可落地的检测规则,并完成语法校验、加载与回放验证。核心要点:自定义 sid 从 1000000 起、用应用层关键字(http.uri/dns.query)提升精度、先 suricata -T 校验再重启服务、告警接入 eve.json 便于后续分析。建议下一步将 Suricata 告警接入 ELK 或现有日志平台,实现攻击事件的可视化与告警联动。