手把手教你落地网络入侵检测系统(NIDS),从选型到上线全记录
说实话,搞安全这块东西,很多运维同学是又爱又恨。爱的是确实能帮你挡住不少事儿,恨的是部署起来各种坑,配不好还一堆误报,搞得你天天看告警看到想吐。
我之前在客户公司负责过一套NIDS的完整落地,从前期调研到最后稳定运行,前前后后折腾了差不多两个月。今天就把这个过程掏出来跟大家聊聊,尽量把踩过的坑和一些实际经验都说清楚。
先搞清楚你到底要监控什么
很多人上来就想装Snort、装Suricata,工具先搞起来再说。我一开始也是这个思路,后来发现这样搞完全是在浪费时间。
你得先坐下来想清楚几个问题:你的网络环境里,哪些流量是需要重点盯着的?敏感数据在哪?常见的威胁类型是什么?
拿我们当时的情况来说,公司有一套对外的Web业务系统,还有内部的OA和数据库集群。对外的业务系统天天被扫描、被尝试SQL注入、XSS什么的,这块肯定是重点。内部的话,主要担心的是横向移动,就是万一有人进来了,在内网里到处乱窜。
我当时列了一个简单的表格:
| 监控区域 | 流量类型 | 关注的威胁 | 优先级 |
|---|---|---|---|
| DMZ区 | HTTP/HTTPS | Web攻击、扫描探测 | 高 |
| 核心交换 | 全流量 | 横向移动、C2通信 | 高 |
| 数据库段 | DB协议流量 | 异常查询、数据外泄 | 中 |
| 办公网 | 混合流量 | 恶意软件、钓鱼 | 中 |
这个表看起来简单,但真的很有用。后面选工具、写规则、部署探针的时候,都是围绕这个来的。不然你部署完了发现,关键的地方没覆盖到,不关键的地方一堆告警,那就白忙活了。
工具选型:Snort还是Suricata?
开源的NIDS工具,绕不开这两个。商业的像Palo Alto、FireEye那些,预算够当然好,但大多数公司的安全预算你懂的...所以我们还是聊开源方案。
Snort 是老牌子了,社区大,规则多,文档也全。但它有个问题,单线程。在流量大的环境里,性能瓶颈很明显。我之前在测试环境里跑过,跑到2Gbps左右的流量就开始丢包了。
Suricata 是后来者,天然支持多线程,性能上确实比Snort强不少。而且它兼容Snort的规则格式,也就是说Snort的规则你拿过来基本能直接用。另外Suricata原生支持输出EVE JSON格式的日志,对接ELK那套东西非常方便。
我们最后选的是Suricata,原因很直接:核心交换那个位置的流量峰值能到5Gbps,Snort扛不住。
不过也不是说Snort就不好。如果你的网络规模不大,流量也就几百兆,Snort完全够用,而且上手更简单一些。
还有一个值得提的是 Zeek(以前叫Bro),严格来说它不算传统的IDS,更偏向于网络流量分析和日志生成。它不做实时告警,但生成的连接日志、DNS日志、HTTP日志这些,拿来做事后分析和威胁狩猎非常好用。我们后来也部署了Zeek,和Suricata配合着用,一个管实时告警,一个管深度分析。
硬件和网络架构怎么搞
工具选好了,接下来就是怎么把流量喂给它。
NIDS是旁路部署的,不像防火墙那样串在链路上。它需要的是流量的镜像副本。一般有两种方式:
1. 交换机端口镜像(SPAN/Mirror Port)
这是最常见的方式。在核心交换机上配一个镜像端口,把需要监控的VLAN流量或者特定端口的流量镜像出来,接到NIDS传感器上。
我们用的是华为的交换机,配置大概长这样:
# 创建观察端口(连接NIDS传感器的端口)
observe-port 1 interface GigabitEthernet 0/0/24
# 配置镜像源端口
interface GigabitEthernet 0/0/1
port-mirroring to observe-port 1 both如果是思科的设备:
monitor session 1 source interface Gi0/1 both
monitor session 1 destination interface Gi0/24这里有个坑要注意:镜像端口的带宽要够。如果你镜像的源端口是10G的,但目标端口只有1G,那流量大的时候肯定丢包。我们当时就吃了这个亏,一开始用的1G口做镜像,结果高峰期丢了将近30%的包,好多攻击流量直接漏掉了。后来换成了10G的口才解决。
2. TAP设备
如果预算允许,用网络TAP(Test Access Point)是更好的选择。TAP是一个硬件设备,直接接在链路上,把流量复制一份出来。它的好处是不依赖交换机的镜像功能,也不会因为交换机负载高而丢包。
我们在DMZ区的出口就用了一个TAP,大概花了几千块钱,买的国产的,效果还行。
传感器的硬件配置
跑Suricata的服务器,配置不能太寒酸。我们用的配置是:
- CPU:Intel Xeon E5-2680 v4(14核28线程)
- 内存:64GB DDR4
- 网卡:Intel X710 10GbE(支持多队列)
- 硬盘:500GB SSD(主要存日志,日志量大的话还得考虑外挂存储)
网卡这块特别说一下,一定要选支持多队列的网卡,这样才能充分利用Suricata的多线程能力。Intel的X710和X520系列都可以。另外,接收镜像流量的网卡不要配IP地址,就让它处于混杂模式(promisc mode),只收不发。
# 设置网卡为混杂模式
ip link set eth1 promisc on
# 关闭网卡的一些offload功能,避免影响抓包
ethtool -K eth1 rx off tx off gro off lro off关闭offload这一步很重要,不然网卡会在硬件层面对数据包做合并处理,Suricata拿到的就不是原始的包了,可能导致检测失败。
Suricata安装和基础配置
以CentOS 7为例,安装过程记录一下:
# 安装EPEL和依赖
yum install epel-release -y
yum install gcc gcc-c++ make automake autoconf libtool pcre-devel \
libpcap-devel libyaml-devel file-devel zlib-devel jansson-devel \
nss-devel libcap-ng-devel libnet-devel lua-devel -y
# 安装Rust(Suricata 6.0+需要)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
# 下载并编译Suricata
wget https://www.openinfosecfoundation.org/download/suricata-6.0.13.tar.gz
tar xzf suricata-6.0.13.tar.gz
cd suricata-6.0.13
./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var \
--enable-nfqueue --enable-lua
make -j$(nproc)
make install
make install-conf当然你也可以直接用包管理器装,省事儿:
# 添加OISF的源
yum install https://copr.fedorainfracloud.org/coprs/jasonish/suricata-stable/repo/epel-7/jasonish-suricata-stable-epel-7.repo
yum install suricata -y装完之后,主配置文件在 /etc/suricata/suricata.yaml,这个文件巨长,有好几千行。但核心要改的地方其实没几个。
# 定义你的内网地址段
vars:
address-groups:
HOME_NET: "[192.168.0.0/16,10.0.0.0/8,172.16.0.0/12]"
EXTERNAL_NET: "!$HOME_NET"
port-groups:
HTTP_PORTS: "80"
SHELLCODE_PORTS: "!80"
SSH_PORTS: "22"
DNS_PORTS: "53"
# 配置监听接口
af-packet:
- interface: eth1
cluster-id: 99
cluster-type: cluster_flow
defrag: yes
use-mmap: yes
tpacket-v3: yes
ring-size: 2048
block-size: 32768
# 配置规则文件路径
default-rule-path: /var/lib/suricata/rules
rule-files:
- suricata.rules
# EVE日志输出配置
outputs:
- eve-log:
enabled: yes
filetype: regular
filename: eve.json
types:
- alert:
tagged-packets: yes
- http:
extended: yes
- dns:
- tls:
extended: yes
- files:
force-magic: yes
- flow这里 HOME_NET 的配置特别重要,一定要设成你实际的内网地址段。Suricata的很多规则都是基于 "从外到内" 或者 "从内到外" 的方向来判断的,如果HOME_NET配错了,很多规则直接就不生效。
af-packet 是Linux上推荐的抓包方式,性能比libpcap好很多。cluster_flow 模式会把同一个连接的数据包分配到同一个线程处理,避免乱序。
规则管理这块水很深
Suricata自带一个规则更新工具 suricata-update,用起来还挺方便的:
# 更新规则
suricata-update
# 查看可用的规则源
suricata-update list-sources
# 启用ET Open规则集(免费的)
suricata-update enable-source et/open
# 启用后重新更新
suricata-updateET Open是Emerging Threats提供的免费规则集,质量还可以,覆盖面也比较广。如果你有预算,可以买ET Pro的订阅,规则更全更新也更快。
但说实话,默认的规则集直接用,你会被告警淹没。我们刚上线的时候,一天产生了将近10万条告警,根本看不过来。大部分都是误报或者低价值的告警。
所以规则调优是必须要做的事情。我的做法是分几步走:
第一步:先跑几天,收集数据
不要急着处理告警,先让它跑着,看看告警的分布情况。
# 统计告警按signature排序
cat /var/log/suricata/eve.json | jq -r 'select(.event_type=="alert") | .alert.signature' | sort | uniq -c | sort -rn | head -30你会发现排在前面的往往就那么几条规则,贡献了80%以上的告警量。
第二步:逐条分析,该禁的禁
比如我们当时排在第一的是一条 ET POLICY GNU/Linux APT User-Agent Outbound likely related to package management 的规则。这条规则检测的是Linux服务器用apt下载软件包的行为,在我们的环境里完全是正常操作,直接禁掉。
# 创建禁用规则列表
echo "2013504" >> /etc/suricata/disable.conf
# 重新更新规则(会自动应用禁用列表)
suricata-update第三步:针对业务写自定义规则
通用规则集不可能覆盖你所有的业务场景。比如我们有个内部系统,正常情况下只有特定的几台服务器会访问数据库的3306端口,如果其他IP去访问了,那就很可疑。这种就得自己写规则:
alert tcp ![$DB_CLIENT_1,$DB_CLIENT_2,$DB_CLIENT_3] any -> $DB_SERVER 3306 (msg:"Unauthorized MySQL Access Attempt"; flow:to_server,established; sid:1000001; rev:1; classtype:policy-violation;)写自定义规则的时候有个技巧,sid从1000001开始编号,这样不会和官方规则集冲突。
还有一个我觉得特别实用的规则,检测内网机器对外发起DNS查询到非公司DNS服务器的情况。因为很多恶意软件会用DNS隧道来做C2通信,而且它们通常不会用你公司内部的DNS服务器:
alert udp $HOME_NET any -> !$COMPANY_DNS 53 (msg:"DNS query to non-corporate DNS server"; sid:1000002; rev:1; classtype:policy-violation;)跟ELK对接,让告警可视化
Suricata产生的eve.json日志,直接看JSON文件肯定不现实。我们用的是经典的ELK方案来做日志收集和可视化。
在Suricata服务器上装Filebeat:
# /etc/filebeat/filebeat.yml
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/suricata/eve.json
json.keys_under_root: true
json.add_error_key: true
output.elasticsearch:
hosts: ["10.0.0.100:9200"]
index: "suricata-%{+yyyy.MM.dd}"
setup.template.name: "suricata"
setup.template.pattern: "suricata-*"然后在Kibana里建个Index Pattern,就能看到所有的告警了。
我建了几个比较实用的Dashboard面板:
- 告警总览:按时间线展示告警数量趋势,能快速发现异常的告警峰值
- Top 10告警规则:看哪些规则触发最多,方便持续调优
- Top 10源IP/目的IP:快速定位可疑的IP地址
- 告警严重等级分布:饼图展示高中低告警的比例
- DNS查询Top 20:配合Zeek的DNS日志,看有没有奇怪的域名查询
有了这些面板,每天早上花10分钟扫一眼,心里就有数了。
别忘了HIDS,两者配合才完整
NIDS看的是网络层面的流量,但有些东西它看不到。比如加密流量(HTTPS),NIDS只能看到TLS握手的信息,里面的内容是看不到的。再比如主机上的文件被篡改了、有人用sudo提权了,这些都是网络层面发现不了的。
所以NIDS和HIDS(主机入侵检测系统)应该配合着用。HIDS推荐OSSEC或者它的分支Wazuh,能监控文件完整性、系统日志、rootkit检测这些。
我们的做法是:NIDS负责盯网络流量,发现扫描、攻击尝试、异常连接这些;HIDS负责盯主机层面,发现文件变更、异常登录、可疑进程这些。两边的告警都汇总到ELK里面,做关联分析。
比如NIDS告警说某个外部IP在对Web服务器做SQL注入尝试,然后HIDS告警说同一台Web服务器上的数据库配置文件被修改了,这两个事件关联起来看,那基本就可以确认是被打进来了。单看任何一边都不一定能确定。
威胁情报集成
光靠规则匹配其实是不够的,因为规则都是已知的模式。如果攻击者用了新的手法,规则库里没有,那就检测不到。
引入威胁情报可以弥补一部分。简单来说就是把已知的恶意IP、恶意域名、恶意文件Hash这些信息喂给NIDS,让它去匹配。
Suricata支持加载IP黑名单,你可以从一些免费的威胁情报源获取数据:
- Abuse.ch 的各种黑名单(SSL黑名单、恶意URL、Botnet C2等)
- AlienVault OTX 的开放威胁情报
- CIRCL 的被动DNS数据
我写了个简单的脚本,每天自动拉取这些情报源,转换成Suricata的规则格式,然后reload:
#!/bin/bash
# 下载Abuse.ch的Botnet C2 IP黑名单
wget -q https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.txt -O /tmp/c2_ips.txt
# 转换成Suricata规则
> /var/lib/suricata/rules/threat_intel.rules
while read ip; do
[[ "$ip" =~ ^#.*$ ]] && continue
[[ -z "$ip" ]] && continue
echo "alert ip $ip any -> \$HOME_NET any (msg:\"TI - Known Botnet C2 IP: $ip\"; sid:$((2000000 + RANDOM)); rev:1; classtype:trojan-activity;)" >> /var/lib/suricata/rules/threat_intel.rules
done < /tmp/c2_ips.txt
# 热重载规则
suricatasc -c reload-rulessuricatasc -c reload-rules 这个命令可以在不重启Suricata的情况下重新加载规则,不会中断检测,很实用。
日常运维和持续优化
系统上线之后,不是说就不用管了。NIDS的运维其实是个持续的过程。
规则更新
我设了个crontab,每天凌晨3点自动更新规则:
0 3 * * * /usr/bin/suricata-update && /usr/bin/suricatasc -c reload-rules性能监控
Suricata自身的性能也要关注。它有个stats日志,记录了丢包率、内存使用等信息:
# suricata.yaml中开启stats
stats:
enabled: yes
interval: 30重点关注 capture.kernel_drops 这个指标,如果丢包率持续上升,说明要么是硬件性能不够了,要么是规则太多导致处理不过来。
我们之前遇到过一次丢包率突然飙升的情况,排查下来发现是有人在内网做大文件传输,流量瞬间冲到了8Gbps,超过了传感器的处理能力。后来的解决办法是在镜像端口上做了过滤,只镜像需要监控的VLAN流量,不相关的大流量传输就不镜像了。
误报处理
这个是永远干不完的活儿。我的经验是建一个误报处理的文档或者wiki,每次处理完一个误报,就记录下来:哪条规则、什么情况触发的、怎么处理的(是禁用规则还是加了例外)。时间长了这就是一份很有价值的知识库。
定期review
每个月抽一天时间,把这个月的告警数据拉出来看一看。哪些规则从来没触发过?是因为确实没有这种威胁,还是因为部署位置不对导致看不到?哪些规则触发太多?是不是需要进一步调优?网络架构有没有变化,需不需要调整探针位置?
关于合规和隐私
这个点很多人会忽略,但其实挺重要的。NIDS抓的是网络流量,里面可能包含用户的个人信息、通信内容这些敏感数据。
我们当时做了几件事:
- 明确了NIDS只用于安全检测目的,不会用来监控员工的上网行为
- 日志的访问权限做了严格控制,只有安全团队的人能看
- 日志保留周期设为90天,过期自动删除
- 在员工手册里加了一条关于网络安全监控的说明
这些东西看起来是走形式,但万一真出了事,有没有这些合规措施,差别还是很大的。
写到这里差不多了。整个NIDS的落地过程,说白了就是:想清楚要监控什么 → 选对工具 → 把流量引过来 → 装好配好 → 写规则调规则 → 接上日志平台 → 持续运营优化。每一步都不难,但每一步都有坑。
最关键的其实是最后一步,持续运营。我见过不少公司花了大价钱买了商业IDS/IPS,装上之后就没人管了,告警从来不看,规则从来不更新,跟没装一样。工具再好,没有人去运营,就是个摆设。
希望这篇文章对正在考虑部署NIDS的朋友有些帮助。如果你在部署过程中遇到什么问题,欢迎留言交流。觉得有用的话,帮忙点个赞转发一下,让更多人看到,感谢!
公众号:运维躬行录
个人博客:躬行笔记