做运维这些年,我一直觉得安全监控里最容易被忽视、却又最关键的一环,就是网络流量的实时检测。防火墙可以挡住显式的恶意连接,但真正能从流量特征层面发现异常、甚至抓出内部失陷主机的工具,还得靠入侵检测系统。Snort作为轻量级IDS的代表,单机部署轻便、规则生态成熟、官方规则库持续更新,特别适合中小规模服务器机群或单点主机做安全基线建设。这篇文章我就围绕Snort的安装、配置和实战使用,结合我在实际环境里踩过的坑,把从零到能跑起来的过程完整梳理一遍。适合刚接触Linux安全的运维同学,也适合想给现有服务器加一道“流量审计”能力的人。
这篇文章不是简单贴命令,我会把每一步“为什么这么做”也讲清楚,比如为什么要开启混杂模式、为什么推荐源码编译、规则语法里那几个容易写错的位置,以及实际检测网络扫描和SSH爆破时怎么调规则才有效。内容比较多,建议对照环境实际操作。
1. Snort的定位、原理与部署模式选择
1.1 Snort到底是什么
Snort是一个开源的网络入侵检测系统(IDS),最早在1998年发布,现在由开源社区持续维护。它本质上是基于规则的流量分析引擎:网卡收到数据包后,Snort根据用户定义的规则对包头的源地址、目的地址、端口、协议类型,以及负载内容里的特征字符串进行匹配,一旦匹配到规则就产生告警或执行响应动作。
严格来说,Snort有三种工作模式:
- 嗅探模式(Sniffer):仅读取并打印网络中的报文,类似tcpdump的增强版。
- 包记录模式(Logger):把报文记录到磁盘,方便事后分析。
- 入侵检测模式(NIDS):在包记录的基础上,加载规则库,实时比对并产生告警。
日常说的“部署Snort做入侵检测”指的就是第三种模式。它部署在旁路或汇聚位置,不会修改流量路径,而是复制一份流量进行分析,因此对现有网络性能影响小,挂掉也不会阻断业务。
1.2 为什么选择Snort作为轻量级IDS
对于预算有限、又不希望引入复杂商业安全平台的团队来说,Snort有四个无法替代的优点:
- 资源占用可控:一个双核CPU、4G内存的小型服务器就能处理百兆到千兆级别的流量分析,核心业务不跑在同一台机器上时,CPU占用通常在10%到30%之间。
- 规则生态丰富:官方有一个持续更新的规则订阅源,社区规则也有几千条,Web攻击、SQL注入、端口扫描、僵尸网络指令等常见攻击特征都能覆盖。
- 二次开发友好:规则就是纯文本,格式清晰,自己编写新规则很简单,还能通过Barnyard2、PulledPork等工具做规则管理和日志输出。
- 与告警平台联动方便:日志可以通过syslog、unified2格式输出,方便对接SIEM或自建告警中心,后期扩展性很强。
1.3 旁路镜像部署与串接部署的区别
我在第一次部署Snort的时候就纠结过:到底要不要把流量串进Snort?后来被前辈一句话点醒:先用旁路镜像把检测跑起来,再考虑是否需要阻断。
- 旁路镜像部署:通过交换机SPAN端口或TAP设备把业务流量复制一份给Snort。Snort只做分析,不介入数据转发。优点是部署风险极低,设备故障不影响业务;缺点是只能告警,不能主动阻断攻击。
- 串接部署(Inline):Snort作为网关的一部分,接收流量后可以切断恶意连接。这是IPS(入侵防御系统)的做法。性能要求高,配置复杂,规则误报可能导致业务中断。
对于入门和绝大多数内部网络审计需求,我建议先做旁路镜像。Snort的角色就是“哨兵”,不是“交警”。想要提醒告警,可以对接脚本自动拉黑IP;想要实时阻断,后续再升级IPS方案。
2. 安装前的思路与依赖环境准备
2.1 源码编译和包管理器安装怎么选
不少Linux发行版自带了Snort包,比如apt install snort、yum install snort,装起来很快,但版本往往比较旧。Ubuntu 20.04仓库里的Snort还是2.9.x早期版本,缺少一些新规则特性。Snort 2.9系列和3.0系列在配置语法、规则引擎上有一些差异,社区规则和工具链更成熟的是2.9.x系列。因此我的建议是:以2.9.20源码编译安装为主,不要图省事用老包。源码安装虽然编译要花几分钟,但能自己控制依赖版本、优化编译选项,后续扩展规则和插件也方便。
另一个原因是很多安全分析工具(如Barnyard2)依赖特定版本的库接口,系统包管理器装出来的Snort路径和库查找路径可能不一致,编译时把prefix指定清楚,后面少踩很多坑。
2.2 操作系统和编译依赖
我以CentOS 7.9为例,Ubuntu等Debian系操作也一样,只是包命令换一下。需要先保证以下依赖齐全:
- gcc、g++编译器
- flex(词法分析器)
- bison(语法分析器)
- make
- libpcap开发库
- libpcre3-dev / pcre-devel
- zlib1g-dev / zlib-devel
- libdnet开发库
- 可选:openssl-devel、luajit、daq库
如果系统本身是精简安装,有些包可能缺失,所以先做一次全量更新和依赖安装。
# CentOS/RHEL系 yum update -y yum install -y gcc gcc-c++ flex bison make libpcap-devel pcre-devel \ libdnet-devel zlib-devel openssl-devel wget vim # Ubuntu/Debian系 apt update apt install -y build-essential flex bison libpcap-dev libpcre3-dev \ libdnet-dev zlib1g-dev libssl-dev wget vim这里有个容易忽略的点:libdnet(数据链路层网络库)在部分发行版里包名不是libdnet-dev,而是libdumbnet-dev。我装CentOS时一直报找不到dnet.h,后来才发现需要单独指定老包的名称。检查方式很简单:
find /usr/include -name "dnet.h"如果系统自带的是dumbnet头文件,需要在配置阶段加上--with-dnet参数,或者做软链接指向正确路径。这个坑等下编译会表现出来。
2.3 DAQ组件必须提前编译
Snort 2.9之后把数据采集抽象层独立成了一个叫DAQ(Data Acquisition)的库,负责从网卡读取数据包并提供给Snort分析。编译Snort之前必须先把DAQ编译安装好,否则配置阶段会报错。
我的建议是下载和Snort版本对应的DAQ版本。Snort 2.9.20对应的DAQ是2.0.7。
wget https://www.snort.org/downloads/snort/daq-2.0.7.tar.gz tar zxvf daq-2.0.7.tar.gz cd daq-2.0.7 ./configure --prefix=/usr/local/daq make && make install如果遇到libpcap版本过新导致的兼容问题,可以加--with-libpcap-includes、--with-libpcap-libraries参数指定路径。另外把DAQ的库目录加入动态链接库搜索路径:
echo "/usr/local/daq/lib" > /etc/ld.so.conf.d/daq.conf ldconfig不执行这一步的话,Snort启动时会报找不到libdaq.so,非常经典。
2.4 网卡混杂模式的准备
Snort要分析流经网卡的所有流量,但默认情况下网卡只处理发给自己的数据包,其他包会被丢弃。要接收全部流量,必须开启混杂模式(Promiscuous Mode)。
在测试环境或者用单个网卡做实验时,可以用命令开启:
ip link set eth0 promisc on但这样重启后就失效了。更合理的做法是写入网卡脚本配置,比如CentOS的/etc/sysconfig/network-scripts/ifcfg-eth0里加一行:
PROMISC=yes或者用systemd的networkd配置,在.network文件里加上:
[Link] Promiscuous=yes如果主机只有一块网卡,而且这台服务器本身还承担业务流量,那Snort会把自身产生的进出流量也一起分析,容易造成重复告警。更标准的做法是:交换机制作端口镜像,Snort服务器只接镜像流量,使用一块专门的网卡。这样分析的数据干净,负载也低。
3. Snort源码编译安装全过程
3.1 下载Snort源码并校验
我习惯把源码下载到/usr/local/src,下载前先确认版本。目前2.9系列最新的稳定版本是2.9.20,官方页面和GitHub都能下到。
cd /usr/local/src wget https://www.snort.org/downloads/snort/snort-2.9.20.tar.gz wget https://www.snort.org/downloads/snort/snort-2.9.20.tar.gz.md5 md5sum -c snort-2.9.20.tar.gz.md5校验这个步骤不要跳。我遇到过下载源不稳定,解压时报unexpected EOF,用md5sum一查就知道文件不完整,避免白编译一场。
3.2 编译安装Snort本体
解压并执行configure:
tar zxvf snort-2.9.20.tar.gz cd snort-2.9.20 ./configure --prefix=/usr/local/snort \ --with-daq-includes=/usr/local/daq/include \ --with-daq-libraries=/usr/local/daq/lib \ --enable-sourcefire \ --enable-open-appid make -j4 make install这里的参数说明:
--prefix=/usr/local/snort:指定安装目录,方便后续管理和卸载。--enable-sourcefire:启用Sourcefire的增强功能,比如部分规则需要的高级特征处理。--enable-open-appid:启用应用识别功能,这个对Web流量的识别很有用,但要求系统里有LuaJIT,如果没有,编译配置会自动降级。没有也不影响核心IDS功能。-j4:编译并行任务数,根据CPU核数调整,不要超过物理核心数。
编译过程中最容易出现的错误是缺少pcre.h或者libpcap.h,按之前的依赖检查补装即可。还有一个常见的链接错误是找不到dnet库,解决方法是确认libdnet-devel或libdumbnet-devel已安装,并在configure时指定:
CPPFLAGS="-I/usr/include/dumbnet" ./configure ...这是我在旧CentOS上踩过的典型问题,因为dumbnet把头文件放在dnet子目录下,导致找不到了。
3.3 建立Snort运行目录与用户
Snort官方推荐不用root运行,降低安全风险。创建专用用户和目录:
groupadd snort useradd -g snort -s /sbin/nologin -c "Snort IDS" snort mkdir -p /usr/local/snort/etc/snort mkdir -p /usr/local/snort/rules mkdir -p /usr/local/snort/var/log/snort如果源码包里已经带了etc下的默认配置文件,可以直接复制。安装目录结构我是这样规划的:
- 配置文件:
/usr/local/snort/etc/snort/ - 规则文件:
/usr/local/snort/rules/ - 日志目录:
/usr/local/snort/var/log/snort/
安装完后,把源码包中自带的规则样本复制过去,主要是classification.config、reference.config、threshold.conf、unicode.map等。
cd /usr/local/src/snort-2.9.20/etc cp *.conf *.config *.map /usr/local/snort/etc/snort/ mkdir -p /usr/local/snort/etc/snort/so_rules这些配置文件是Snort能正确加载规则的基础,缺少了会导致规则解析报错。
3.4 验证安装成功
编译完成后先执行版本确认:
/usr/local/snort/bin/snort -V正常会输出类似:
,,_ -*> Snort! <*- o" )~ Version 2.9.20 GRE (Build 52) '''' By Martin Roesch & The Snort Team http://www.snort.org看到版本号就说明编译成功了。如果提示找不到某个动态库,用ldd检查:
ldd /usr/local/snort/bin/snort | grep "not found"然后按缺失的库名补安装或配置ldconfig路径即可。
4. Snort核心配置文件深度拆解
4.1 snort.conf整体逻辑
snort.conf是Snort的总入口。它不直接在文件里写规则,而是定义了网络变量、动态加载的库、预处理配置、输出配置,以及包含哪些规则文件。
第一次打开默认的snort.conf,会看到大量include语句。这些语句决定了检查哪些规则。我们不需要全部启用,按照自己的网络环境调整网络变量,再按需要选择规则集即可。
下面是我在配置里重点改的几处。
4.2 网络变量配置,这是重中之重
Snort规则里大量使用了变量,比如$HOME_NET表示本地网络、$EXTERNAL_NET表示外部网络。如果这两个变量配置错误,很多规则就会误判内外方向。比如内部IP段是192.168.1.0/24,而HOME_NET写成了any,那原本针对外部攻击者的规则也会匹配内部主机,产生一堆噪音。
我的标准配置如下:
ipvar HOME_NET 192.168.1.0/24 ipvar EXTERNAL_NET !$HOME_NET ipvar DNS_SERVERS 192.168.1.53 ipvar SMTP_SERVERS $HOME_NET ipvar HTTP_SERVERS $HOME_NET ipvar SQL_SERVERS 192.168.1.50 ipvar TELNET_SERVERS $HOME_NET对于像阿里云、腾讯云这类有默认公网IP的服务器,还可以把HOME_NET写成多段:
ipvar HOME_NET [10.10.0.0/16,172.16.0.0/12,192.168.0.0/16]注意中间的逗号和空格。EXTERNAL_NET中的!表示“非”,这是Snort语法里常用的单目操作符。
另外要修改PORT变量,比如默认的HTTP_PORTS是80,如果服务器跑在8080,就要补上:
portvar HTTP_PORTS [80,8080] portvar SHELLCODE_PORTS !0这些变量被大量规则引用,漏改会导致规则匹配不到正确的端口。
4.3 预处理配置与启用方式
预处理是Snort在规则匹配之前对数据包做的深度协议解析。官方注释里默认是关闭的,需要手动开启。常见的预处理模块有:
frag3:IP分片重组,防止分片攻击绕过规则。stream5:TCP流重组,让规则能跨多个数据包匹配会话内容。http_inspect:HTTP流量解析,解码URL、请求体。sfPortscan:端口扫描检测。
我建议至少开启stream5和sfPortscan,因为很多攻击特征(比如SQL注入)分散在多个TCP分段里,不重组根本匹配不出来。
示例配置(写在预处理部分):
preprocessor frag3_global preprocessor frag3_engine: policy windows, detect_anomalies, overlap_limit 10, min_fragment_length 100, timeout 60 preprocessor stream5_global: track_tcp yes, track_udp yes, track_icmp yes, max_tcp 262144 preprocessor stream5_tcp: policy windows, bind_to 0.0.0.0, use_static_footprint_sizes, \ max_queued_bytes 2048, max_queued_segments 2621, \ timeout 180, overlap_limit 10 preprocessor http_inspect: global iis_unicode_map unicode.map 1252 preprocessor http_inspect_server: server default \ profile all ports { 80 8080 8000 } \ oversize_dir_length 500 \ unicode_map unicode.map 1252 preprocessor sfportscan: proto { all } memcap { 10000000 } sense_level { high } \ logfile { portscan.log } watch_ip { $HOME_NET }留意sfPortscan的memcap控制内存上限,在大流量场景下要适当调大,否则会出现丢检测。sense_level设为high会提高敏感度,但也会增加误报,生产环境建议从medium开始试验。
4.4 输出插件:把告警写到哪里
Snort的告警默认打印到控制台,也可以在snort.conf里配置输出插件,把告警写到数据库、syslog、unified2等。在2.9.x中,推荐使用unified2二进制格式,因为它写入性能高,不容易丢日志,后续通过Barnyard2解析入库,或者丢给其他平台。
在snort.conf里找到output配置,改成:
output unified2: filename snort.log, limit 128 output alert_syslog: LOG_AUTH LOG_ALERTlimit 128表示单个日志文件达到128MB后自动滚动,防止磁盘被撑满。如果想便于测试,可以在命令行临时用-A console,不需要改配置。
4.5 规则加载路径与include组织方式
不要直接把成千上万条规则一股脑放进snort.conf里,而是分目录管理。我采用这样一套规则组织方式:
/usr/local/snort/rules/ ├── snort.rules # 本地自定义规则 ├── local.rules # 临时测试规则 ├── emerging.rules # 社区规则(按需子集) └── so_rules/在snort.conf中最后部分,注释掉默认自带的那些include,只保留需要的:不要一次性全include,很多自带规则依赖特定配置,缺少会导致启动报错。比如注释掉include $RULE_PATH/attack-responses.rules,只保留基础的和本地规则。
include $RULE_PATH/snort.rules include $RULE_PATH/local.rules如果下载了社区规则集,再按类别include,比如:
include $RULE_PATH/emerging-scan.rules include $RULE_PATH/emerging-web_server.rules4.6 配置文件语法自检
每次修改snort.conf后,用-T参数测试配置,这是最安全的自检方式:
/usr/local/snort/bin/snort -T -c /usr/local/snort/etc/snort/snort.conf如果看到:
Snort successfully validated the configuration! Snort exiting说明配置没问题。如果哪里出错,它会明确指出哪个文件哪一行有问题。我每次调整规则或变量都会跑一遍,养成习惯,能避免很多线上启动失败的问题。
5. 规则管理与告警规则编写
5.1 从哪获取规则
Snort的规则来源主要有几类:
- 官方注册规则:需要到Snort官网注册账号并订阅,有免费和付费的TALOS规则,免费规则更新延迟30天。
- 社区规则集:比如Emerging Threats,有开放的规则发布。
- 本地自定义规则:根据自己业务和攻击特征编写,这是最能体现运营能力的部分。
不要在测试阶段盲目全量加载规则,建议先从local.rules和少量社区规则开始,验证检测效果后再逐步扩展。
5.2 规则语法格式
Snort规则由规则头和规则选项两部分组成。一个最简单的规则:
alert icmp any any -> $HOME_NET any (msg:"ICMP Ping Detected"; sid:1000001; rev:1;)alert:动作,出现匹配时告警。icmp:协议类型。any any:源IP和源端口。->:方向。$HOME_NET any:目标IP和目标端口。msg:告警信息。sid:规则唯一ID,1000000以上留给本地自定义,避免与官方规则冲突。rev:版本号,每次修改递增。
再举一个检测SSH暴力破解的例子。SSH爆破的特征是短时间内同源IP大量连接22端口,纯规则本身做不了状态统计,但可以配合Snort的rate_filter功能。
在rules文件里加一个基础的SSH访问规则:
alert tcp $EXTERNAL_NET any -> $HOME_NET 22 (msg:"SSH Connection Attempt"; sid:1000002; rev:1;)然后在snort.conf中加阈值或速率限制:
suppress gen_id 1, sig_id 1000002, track by_src, ip 10.10.10.10更推荐使用rate_filter语法,在snort.conf中加入:
rate_filter alert gen_id 1, sig_id 1000002, \ track by_src, count 10, seconds 60, \ new_action alert, timeout 120意思是同源IP在60秒内触发规则超过10次,就把后续匹配事件升级为alert并持续120秒。这种检测比纯静态规则实用得多。
5.3 规则的分类与优先级
Snort里规则动作还有log、pass、drop(需要inline模式)等。生产环境需要根据风险级别设置优先级。规则选项里的classtype和priority可以标记威胁等级,比如:
alert tcp $EXTERNAL_NET any -> $HOME_NET 80 \ (msg:"SQL Injection Detected"; flow:to_server,established; \ content:"union select"; nocase; classtype:web-application-attack; \ sid:1000003; rev:1;)flow:to_server,established确保只检查已建立连接且发往服务器的包,避免对响应包做重复匹配。content:"union select"是要查找的特征字符串。规则编写的一个重要原则是尽量最严格的模式匹配组合,如果只写一个很宽泛的content,误报率会非常高。例如检查SQL注入时,除了union select,还应该加上%00或注释符号--等特征,再限制http_uri,才能降低误报。
5.4 使用PulledPork管理规则更新(可选)
当规则文件多了以后,手动更新很痛苦。可以用PulledPork这个工具自动下载和更新规则集。安装配置比较复杂,入门阶段可以先手动管理,等上了规模再引入自动化。PulledPork的主要作用是:
- 从规则源下载新规则
- 启用或关闭部分规则
- 生成sorted.rules供snort.conf包含
如果你未来有几百台设备,这个工具是必学的,但当前文章先不展开,避免主线变乱。
6. Snort启动、日志读取与实战检测
6.1 创建systemd服务实现开机自启
不像tcpdump用完就结束了,入侵检测需要7x24小时运行。用一个systemd服务管理Snort最省心。
新建/etc/systemd/system/snort.service:
[Unit] Description=Snort NIDS After=network.target [Service] Type=simple ExecStart=/usr/local/snort/bin/snort -q -u snort -g snort \ -c /usr/local/snort/etc/snort/snort.conf \ -D -i eth1 -l /usr/local/snort/var/log/snort \ --pid-path=/var/run/snort ExecReload=/bin/kill -HUP $MAINPID Restart=on-failure [Install] WantedBy=multi-user.target参数说明:
-q:安静模式,减少无关屏幕输出。-u snort -g snort:以非root用户运行。-D:守护进程模式。-i eth1:监听eth1接口,按实际镜像网卡修改。-l:日志目录。--pid-path:PID文件位置。
启动前先确保日志目录属主改为snort:
chown -R snort:snort /usr/local/snort/var/log/snort chown -R snort:snort /usr/local/snort/rules systemctl daemon-reload systemctl start snort systemctl enable snort查看运行状态和实时日志:
systemctl status snort journalctl -u snort -f6.2 实战:用ping检测ICMP规则
现在做一个小实验,验证Snort是否真正在工作。
在一台客户端(比如192.168.1.10)上执行:
ping -c 4 192.168.1.1Snort主机监听镜像端口,应该能看到ICMP流量。如果我们在local.rules里有这样一条规则:
alert icmp $EXTERNAL_NET any -> $HOME_NET any (msg:"ICMP Ping Detected"; sid:1000001; rev:1;)那么ping包到达后会生成一条告警。查看方式:
tail -n 20 /usr/local/snort/var/log/snort/alerts实际数据里会有一行包含ICMP Ping Detected和源IP、目的IP、时间戳。Snort写alert时默认会追加到文件,格式是二进制还是文本,取决于输出插件。如果用unified2输出,需要工具解析,后面再讲。
6.3 实战:检测端口扫描
用nmap从外部主机扫一下Snort所在主机或同网段主机,观察sfPortscan模块是否报警。
测试命令:
nmap -sS -p 1-1000 192.168.1.1如果snort.conf里开启了sfPortscan,日志文件portscan.log里会产生扫描预警。查看:
cat /usr/local/snort/var/log/snort/portscan.log如果没看到,可能原因有三种:
- 扫描目标的IP没有包含在
watch_ip中;把watch_ip改成$HOME_NET再试。 sense_level设置太低,把攻击特征忽略了;调成high重试。- 镜像流量根本没有到Snort网卡;用tcpdump验证一下镜像口是否真的有流量。
端口扫描检测对性能有一定影响,生产环境建议结合memcap参数调整,发现内存占用过高时调低max_queued_segments或增加内存限制,避免Snort进程被OOM杀掉。
6.4 实战:SSH爆破行为的发现
模拟SSH爆破,在客户端用脚本快速尝试登录:
for i in $(seq 1 20); do ssh 192.168.1.1 -p22 exit; doneSnort会看到22端口的连接尝试。但只有一条“SSH Connection Attempt”规则时,只会逐条产生告警,刷屏很严重。更好的是配合rate_filter做聚合报警,我在生产环境里就是这样做的。
在snort.conf里加:
rate_filter alert gen_id 1, sig_id 1000002, \ track by_src, count 8, seconds 30, \ new_action log, timeout 120含义:30秒内同源IP触发SSH尝试规则8次以上时,生成一条新的聚合日志。这样告警日志量大幅下降,且能一眼看到哪个IP在爆破。
6.5 日志文件的读取与Alerts解析
当使用unified2输出时,/usr/local/snort/var/log/snort/下会生成snort.log.xxxxxx文件,这类文件需要使用Barnyard2或者u2boat工具解析成可读文本。
Barnyard2是一个单独的软件包,专门读取Snort 2.9的unified2文件并输出到数据库或文本。编译安装过程类似:
wget https://github.com/.../barnyard2-master.tar.gz ./configure --with-mysql --with-snort /usr/local/snort make && make install安装完后配置barnyard2.conf,指定:
config waldo_file: /usr/local/snort/var/log/snort/barnyard2.waldo output alert_fast: /usr/local/snort/var/log/snort/alert_fast.log然后运行:
barnyard2 -c /usr/local/snort/etc/barnyard2.conf \ -d /usr/local/snort/var/log/snort \ -f snort.log \ -l /usr/local/snort/var/log/snort \ -w /usr/local/snort/var/log/snort/waldo它会持续监控新的snort.log文件并转为文本告警。如果暂时不想装Barnyard2,测试阶段可以直接在snort.conf里配置成文本输出:
output alert_fast: /usr/local/snort/var/log/snort/alert_fast.log这样实时日志直接写在文本文件里,调试规则更直观。生产环境建议unified2,因为写磁盘更稳定,不易丢数据。
6.6 性能监控与调优命令
Snort运行中如何确认它没有“掉链子”?几个重要指标:
- 丢包率:运行
/usr/local/snort/bin/snort --pid-file=...不方便看,更好的办法是使用snort -q ... &方式不好调。可以用top看CPU占用,但更精细需要启用性能统计。
在snort.conf里加:
config profile然后重启Snort,它会周期性输出每个检测模块的耗时统计,用于定位性能瓶颈。再配合系统层面的iftop、nload看网卡流量速率。
如果发现丢包,先看线速率是否超过网卡能力,再看DAQ的pcap模式是否有性能瓶颈,必要时把DAQ换成afpacket模式,在启动行加:
--daq afpacket -i eth1:eth1afpacket模式使用内核的AF_PACKET v3机制,批量收包,吞吐比传统pcap高不少。但这要求DAQ编译时启用afpacket支持,编译DAQ时加--enable-afpacket即可。
7. 常见问题与排查技巧实录
7.1 启动时报FATAL: Failed to open DB
这个报错和输出插件有关。如果在snort.conf里配置了output database指向MySQL,但MySQL服务没启动或连接串写错,就会出现这个错。快速定位方法是先用-T测试配置,看是不是输出插件参数不合法。
经验:刚开始学习Snort时,不要一上来就配数据库输出,先用unified2或文本日志跑通全链路,后面再加数据库层。
7.2 界面网卡没有流量
Snort看起来在跑,但永远没有任何检测事件。第一件事不是怀疑规则,而是用最基础的工具验证流量是否到达:
tcpdump -i eth1 icmp如果在Snort主机上执行ping后tcpdump都抓不到包,说明镜像链路没有做通;这时候去查交换机的SPAN配置或者TAP设备接线。我遇到过交换机SPAN口和目的端口带宽不匹配导致丢包,后来换了高带宽端口才稳定。
7.3 误报太多,如何降噪
Snort刚装好,常见的是各种规则疯狂告警,尤其是扫描、SSL探测、奇怪的HTTP方法。降噪有个三板斧:
- 修订
HOME_NET,确保内网IP范围准确。 - 过滤掉已知的合法监控或业务流量,在snort.conf里用
pass规则先丢弃噪声。例如内网自己的漏洞扫描器:
pass ip 10.10.10.9 any -> $HOME_NET any (msg:"Exclude scanner"; sid:2000001; rev:1;)- 给规则加白名单或阈值,用
threshold和rate_filter减少重复告警。
不要一上来就删规则,环境里保留完整的规则集对后续分析有好处,降噪手段用阈值和pass更好。
7.4 SNORT service restarts,无法开机自启
之前遇到过systemd服务启动失败,检查journalctl -xe发现权限错误。原因是Snort以snort用户运行时,PID文件目录/var/run/snort不存在,或者不支持创建。
解决方法是服务文件里加:
ExecStartPre=/bin/mkdir -p /var/run/snort ExecStartPre=/bin/chown snort:snort /var/run/snort同时确保日志目录和PID目录都属于snort用户。重启后一切正常。
7.5 日志磁盘被写满的防范
IDS会持续写日志,特别是unified2文件,一天下来可能几个GB。几条经验:
- snort.conf里
output unified2: filename snort.log, limit 128,设置单文件大小上限,避免单个文件无限增长。 - 用logrotate定期清理旧日志。
- 生产环境建议日志目录单独挂载,哪怕只分配几十GB,也能防止主系统盘被写爆。
我自己还写了一个简单的轮转脚本,每天压缩归档7天前的日志,再清理30天前的文件。这个小习惯让snort日志目录长期保持可控。
7.6 规则不生效,找不到事件
规则不生效的情况很多,最常见的是:
- 规则文件没有被include进snort.conf,检查include路径是否正确。
- 规则的协议和方向与流量方向不匹配,比如内网到外网的SSH,规则写的是
$EXTERNAL_NET -> $HOME_NET,方向反了。 - 规则中的
content匹配条件太严格,比如负载特征实际大小写不对,又没有加nocase。 - 规则被全局的
suppress或threshold压制。
排查手段用-A console前台运行并指定单个规则文件,减小干扰:
snort -A console -c snort.conf -i eth1然后手动触发流量,立刻在屏幕上看到事件。这比事后翻日志直观得多。
8. 延伸经验:规则调试与后续联动
8.1 单条规则调试的小技巧
想快速验证一条自定义规则是否有效,我建议不必启动完整Snort,直接用snort -c 自定义规则文件 -r 抓包文件来离线分析。
先抓一个包含攻击特征的pcap文件:
tcpdump -i eth1 -w test.pcap host 192.168.1.10再离线测试规则:
/usr/local/snort/bin/snort -c /usr/local/snort/rules/test_rule.rules \ -r test.pcap -A console这条命令会直接打印匹配到的告警。离线模式不依赖网卡环境,非常适合写新规则时的快速验证。我所有重要的自定义规则,都会先用pcap验证再去生产环境加载,避免上线即刷屏。
8.2 Snort与SIEM系统联动
Snort的告警如果只是躺在日志文件里,价值很有限。生产上更常见的是把snort日志交给SIEM平台。如果是文本日志,可以用filebeat采集;如果是unified2库,让barnyard2写进数据库,再对接平台。我当时在一个监控项目里,用filebeat采集alert_fast.log,通过kafka传到es查询,整个链路性能稳定,告警还能配合威胁情报做ip封禁。
最小化的联动脚本可以这样做:监控snort的alert_fast.log,发现高危签名时用shell调防火墙封禁源IP。例如:
tail -F /usr/local/snort/var/log/snort/alert_fast.log | while read line; do src_ip=$(echo $line | grep -oE "([0-9]{1,3}\.){3}[0-9]{1,3}" | head -1) if [ -n "$src_ip" ]; then iptables -A INPUT -s $src_ip -j DROP fi done这只是一个粗糙的自动阻断尝试,生产环境要注意误报的自锁风险,建议结合置信度评分和人工复核。
8.3 从Snort到Suricata的迁移构想
很多人问:既然Snort好用,为什么还要考虑Suricata?Suricata是另一个开源IDS引擎,多线程设计,单机性能上限更高,规则兼容Snort格式。如果以后流量规模增大,Snort单线程pcap模式处理不过来,迁移到Suricata是一个自然的方向。规则文件大部分可以直接复用,只是配置语法略有变化。
但在中低流量环境下,Snort的稳定性和文档成熟度依然是优势。我目前还有大量小站点继续跑Snort,没有强行升级的迫切需求。技术选型不是看最新,而是看是否满足当前规模和运维能力。
9. 写在最后的实操体会
Snort这套东西,说到底就是个匹配引擎,真正要花心思的是规则裁剪和日常监控运营。我见过很多刚接触IDS的朋友,装上Snort后加载了全套规则,三天不看一次日志,告警堆积如山,很快失去耐心。我的建议是先从最小规则集跑起来,用几天时间观察正常业务基线,再逐步增加规则,边跑边调阈值。
还有一个容易被忽略的点:Snort主机的时钟。告警日志如果没有准确的系统时间,分析溯源时很难对得上攻击链。我后期在每台监控机上配了时间同步服务,让Snort、数据库、SIEM的时间线对齐,这比装一堆复杂组件划算得多。
另外,日志记得冗余一份到远程存储。之前一台监控机磁盘损坏,本地告警全丢,还好每天凌晨同步走了备份,不然那几天的安全记录完全无法追溯。日常运维里,这类不起眼的习惯往往比技术本身的“高深”更能保命,希望对你有用。