梁本来 朱 磊
1(中山职业技术学院信息工程学院 广东 中山 528404) 2(西安理工大学计算机科学与工程学院 陕西 西安 710048)
高速率网络带来的流量激增,使得网络入侵检测系统(Network Intrusion Detection System, NIDS)的检测性能出现瓶颈,传统的单检测引擎NIDS难以实时处理高速率流量。因此,基于多引擎并行检测的NIDS是当今的研究重点与趋势[1-2]。特别指出,并行NIDS与分布式NIDS 并不相同,分布式NIDS将多个检测引擎分布在网络的不同物理位置检测不同处的网络流量,而并行NIDS则将多个检测引擎分布在网络的同一个物理位置,检测同一处的网络流量。尽管两者不同,但分布式NIDS也会用到并行检测,两者有相通之处[3-4]。
为充分发挥并行NIDS的高效性能, 应在保持攻击证据的前提下,尽量通过流量调度实现多检测引擎的负载均衡。目前,并行NIDS的负载均衡算法主要分为静态算法和动态算法两大类[5-6]。静态算法按照设定的策略进行流量调度,多采用Hash函数映射来实现[7],该类算法的优点是不会破坏数据流的完整性,攻击证据保持较好,缺点是难以适应实际动态网络环境,各检测引擎的负载均衡效果较差。动态算法根据检测引擎负载的实时变化,动态调度网络流量,优点是负载均衡效果较好,缺点是容易破坏流量的完整性,保持攻击证据的难度相对较大,算法复杂度较高[8]。动态负载均衡算法又分为激活策略和前摄策略两类,激活策略算法调度流量到检测引擎前不考虑引擎负载,但当某个引擎负载超过设定阈值时,激活算法,将流量从负载较重的引擎迁移到负载较轻的引擎。文献[9]提出的多检测引擎监测的动态负载均衡算法,文献[10]提出的分布式入侵检测中基于能力与负载的数据分割算法,以及文献[11]提出的动态层次负载均衡算法,均是激活策略算法。此类算法针对性强,负载均衡效果较好,但会带来检测引擎间的通信量较大的问题,在实际应用中会额外占用检测引擎的计算资源,导致NIDS的检测性能下降。前摄策略算法在流量调度前就根据各检测引擎的实时负载,动态调度流量,确保各检测引擎的负载均衡。文献[12]提出的并行入侵检测系统的预测负载均衡方法,以及文献[13]提出的一种基于“最小PPS(Packet Per Second)”的动态流量调度策略,均采用了前摄策略思想。此类算法不需要检测引擎间的大量通信,额外占用检测引擎的计算资源较小,但需要采取较为科学的方法将流量按类划分调度到不同的检测引擎,且不能破坏数据流的完整性,尽量保持攻击证据。但以上并行入侵检测方法都存在相应优缺点,在保持攻击证据与多引擎负载均衡之间难以全面提升。
分析攻击特征,可将攻击分为单连接攻击以及多连接攻击两大类[14]。前者攻击特征分布在同一条数据流的报文中,多数攻击属于此类攻击,比如利用操作系统漏洞或程序漏洞发起的攻击;后者攻击特征分布在不同数据流的报文中,比如分布式拒绝服务(Distributed Denial of Service, DDoS)、扫描(Scan)等攻击。
以上文献提出的入侵检测负载均衡算法多是分析单连接攻击,而忽略了多连接攻击,造成多连接攻击的流量被调度至不同检测引擎,而检测引擎间又缺少互相通信获取全局信息的机制,导致攻击证据的丢失。为解决此类问题,本文提出基于攻击分类的高性能并行入侵检测方法,将NIDS分为单连接攻击检测和多连接攻击检测两个子系统。其中,多连接攻击检测子系统采用单检测引擎,快速扫描报文首部,识别相应攻击行为;单连接攻击检测子系统采用多检测引擎并行检测,将流量按照传输层协议分类,以会话或五元组为单位,将流量调度至负载最轻的检测引擎,既能保持攻击证据,又动态实现了负载均衡,且额外占用检测引擎的计算资源较少。
方法思路如图1所示。
图1 基于攻击分类的并行入侵检测方法实现结构图
(1) 多连接攻击检测子系统由高性能检测引擎SensorB组成,其从镜像口2拷贝网络流量。为提高检测效率,SensorB基于Snort 3.0系统改进,在原有规则库中仅保留多连接攻击规则文件,快速检测报文首部,识别多连接攻击行为。
(2) 单连接攻击检测子系统由SensorA1、A2、…、An等检测引擎组成,基于Snort 3.0系统改进,在原有规则库中仅保留单连接攻击规则文件。因单连接攻击行为复杂多样,为保持攻击证据并实现各检测引擎的负载均衡,先由负载均衡模块对镜像口1拷贝的网络流量进行流量调度。
(3) 负载均衡模块由流量调度及负载监控两个子模块组成。其中,负载监控子模块实时监视SensorA1、A2、…、An的负载,计算出负载最轻的检测引擎;流量调度子模块将网络流量按照TCP、UDP以及其他协议进行分类,并触发以下流量调度策略。
① TCP流量以会话为单位进行调度。每个会话的第一个报文被调度至当前负载最轻的检测引擎Am(m=1,2,…,n),相同会话的其他报文也被调度至Am。此方法可以保证同一会话的TCP报文被调度到同一个检测引擎。
② UDP流量以五元组(源IP,源端口,目的IP,目的端口,协议类型)为单位进行调度。如果报文的五元组是第一次出现,则将该报文调度至当前负载最轻的检测引擎Am,与该五元组相同的其他报文,统一被调度至Am。此方法可以保证相同五元组的UDP报文被调度到同一个检测引擎。
③ 其他流量,则直接以报文为单位,调度至当前负载最轻的检测引擎。
方法流程如图2所示。
图2 基于攻击分类的并行入侵检测方法流程
负载均衡算法运行在负载均衡模块,是本文所提入侵检测方法的核心算法,作用于单连接攻击检测子系统,在保持单连接攻击证据的前提下实现多检测引擎的负载均衡。
Pi:接收到的第i个报文,其中i=1,2,…;
Conn_num:目前所记录的五元组数目(五元组信息不同时才计数,初始为0);
Max_num:一个周期内的五元组个数阈值;
Conn(Pi):报文Pi的五元组;
Conn(Pi).flag:Conn(Pi)的标记;
Conn(Pi).seq:Conn(Pi)的序号;
Conn(Pi).sensor:Conn(Pi) 指向的检测引擎;
Am:当前负载最轻的检测引擎;
Pi.SYN:TCP报文Pi的SYN位数值;
Pi.FIN:TCP报文Pi的FIN位数值;
Pi.RST:TCP报文Pi的RST位数值;
Pi.SEQ:TCP报文Pi的序号。
定义1报文五元组
报文Pi的五元组定义如下:
Conn(Pi)=(Pi.srcIP,Pi.srcPort,Pi.dstIP,Pi.dstPort,Pi.proType)
(1)
式中:srcIP表示源IP;srcPort表示源端口;dstIP表示目的IP;dstPort表示目的端口;proType表示传输层协议。
定义2相同五元组
如果报文Pi和Pj存在以下关系
(2)
则Conn(Pi)=Conn(Pj),相同五元组由同一个内存空间存储,改变Conn(Pi)的flag、seq、sensor的取值,即是改变Conn(Pj)对应的数值。
定义3检测引擎的负载
定义SensorAi的负载计算公式如下:
Load(Ai)=a·L(CPUi)+b·L(Memi)+c·L(Busi)
(3)
式中:L(CPUi)表示Ai的CPU利用率;L(Memi)表示Ai的内存利用率;L(Busi)表示Ai的链路带宽利用率。a、b、c分别为权重系数,a+b+c=1。参考文献[10],a取值为0.4,b取值为0.3,c取值为0.3。
定义4负载最轻的检测引擎
如果Sensor Am的负载满足以下公式:
Load(Am)=min{Load(A1),Load(A2),…,Load(An)}
(4)
则SensorAm就是负载最轻的检测引擎。
以一个运行周期为例,算法伪代码描述如下:
算法1负载均衡算法
For(Pi=P1;Conn_num<=Max_num;i++)
{if(Pi.proType!=TCP&&Pi.proType!=UDP)
//TCP、UDP之外的报文
Piwill be sent to SensorAm;
//当前负载最轻引擎Am
else
if(Conn(Pi) is new)
//该五元组是第一次出现
{Conn(Pi).flag=0;
//初始化flag
Conn_num++;
//五元组计数加1
if(Pi.proType==TCP)
//五元组是第一次出现,且是TCP报文
Conn(Pi).seq=0;}
//初始化seq
if(Pi.proType==TCP)
//TCP报文
{if(Conn(Pi).flag==0)
//会话的第一个报文
{Piwill be sent to SensorAm;
//当前负载最轻引擎Am
Conn(Pi).sensor=Am;
//该会话对应的引擎为Am
Conn(Pi).flag=1;}
else
//不是会话的第一个报文
Piwill be sent toConn(Pi).Sensor;
//被调度至会话对应的引擎
if(Pi.FIN==1&&Conn(Pi).seq==0)
//第一个FIN报文
Conn(Pi).seq=Pi.SEQ;
if(Pi.SEQ==Conn(Pi).seq+1‖Pi.RST==1)
//会话最后一个报文或异常关闭报文
{Conn(Pi).flag=0;
Conn(Pi).seq=0;}
if(Pi.proType==UDP)
//UDP报文
if(Conn (Pi).flag==0)
//该五元组第一个UDP报文
{Piwill be sent to SensorAm;
//当前负载最轻引擎Am
Conn (Pi).Sensor=Am;
//该五元组对应引擎为Am
Conn (Pi).flag=1;}
else
//不是该五元组第一个UDP报文
Piwill be sent to Conn (Pi).Sensor;
//被调度至该五元组对应的引擎
}
一个周期内,算法1需要循环调度Max_num个不同五元组的报文,假设每个五元组下包含的报文平均数为C,则需要调度的TCP、UDP报文数为C·Max_num;假设需要调度的TCP、UDP之外的报文数为Other_num,则算法1需要运行C·Max_num+Other_num次,而在循环体内并没有嵌套循环,因此,以一个周期为计算单位,算法的时间复杂度为O(C·Max_num+Other_num)。
一个五元组中,IP地址占用32 bit存储空间,端口占用16 bit存储空间,proType只有TCP、UDP两种状态,需1 bit存储空间,因此一个五元组占用97 bit的存储空间。还需要记录该五元组的sensor、flag和seq,假设检测引擎个数为n,则sensor需要「log2n⎤bit的存储空间;flag只有0,1两种状态,需要1 bit存储空间;seq记录报文的序号,需要32 bit的存储空间。因此,每个五元组的sensor、flag和seq需要占用33+「log2n⎤bit的存储空间。一个周期内,算法1处理的五元组数目为Max_num,因此总共需要(130+「log2n⎤)Max_numbit的存储空间。另外,Conn_num变量最大取值为Max_num,需要占用「log2Max_num⎤bit的存储空间。因此,算法1总共需要(130+「log2n⎤+「log2Max_num⎤)·Max_numbit的存储空间。
通过以上分析可以看出,算法1的时空复杂度并不复杂,但仍可以通过降低Max_num数值减少时空复杂度。不过Max_num取值过小,会导致每一个运行周期过短,过渡切割了攻击流量,难以完整地检测到攻击行为,因此Max_num的取值也是值得分析的一个问题。
以下定理都是基于同一个算法运行周期。
定理1TCP报文Pi被调度前,若Conn(Pi).flag标记为0时,则Pi是会话的第一个报文;Conn(Pi).flag标记为1时,则Pi不是会话的第一个报文。
证明: 基于Conn(Pi)五元组的TCP连接中可能包含多个会话,假设Pi是第一个会话的第一个报文,则Conn(Pi) 一定是新出现的五元组,因此Conn(Pi).flag被初始化为0,且因Pi为TCP报文,Conn(Pi).seq也被初始化为0;报文Pi被调度后,Conn(Pi).flag赋值为1。
该会话之后的报文被调度后,Conn(Pi).flag一直保持为1;第一个终止连接的报文被调度后,由于其FIN位为1,且Conn(Pi).seq==0,因此Conn(Pi).seq=Pi.SEQ;直到第一个会话的最后一个报文被调度完成后,由于满足Pi.SEQ==Conn(Pi).seq+1,Conn(Pi).flag及Conn(Pi).seq均被重新赋值为0。
假如第一个会话过程中,碰到了Pi.RST==1的异常情况,则需要立即终止连接,Conn(Pi).flag及Conn(Pi).seq均被重新赋值为0。
因此,第二个会话的第一个报文被调度前,Conn(Pi).flag已被重新赋值为0。
以此类推可以得出,在Conn(Pi)连接中,每个会话的第一个报文被调度前,Conn(Pi).flag数值为0。每个会话的第一个报文被调度后,Conn(Pi).flag数值为1;之后Conn(Pi).flag数值保持为1不变,直到每个会话的最后一个报文被调度后,Conn(Pi).flag重新为0。
证毕。
定理2UDP报文Pi被调度前,若Conn(Pi).flag标记为0时,表示报文Pi是五元组Conn(Pi)的第一个报文;Conn(Pi).flag为1时,表示报文Pi不是Conn(Pi).的第一个报文。
证明:假设UDP报文Pi是五元组Conn(Pi)的第一个报文,则Conn(Pi)一定是新出现的五元组,因此Conn(Pi).flag被初始化为0,且报文Pi经过调度后,Conn(Pi).flag被赋值为1。
假设Pi是Conn(Pi)连接的第j(j≠1)个报文,经过上述分析得知,该报文被调度前,Conn(Pi).flag为1。
证毕。
定理3同一TCP会话下的所有报文,被调度至同一检测引擎。
证明: 标记该TCP会话为S,由证明1可以得出,会话S的第一个报文PS1被调度前,由于Conn(PS1).flag标记为0,PS1被调度至当前负载最低的检测引擎Am,且标记Conn(PS1).sensor=Am。
令PSi表示为会话S的第i个报文(i≠1),由于PSi和PS1同属于会话S,则Conn(PSi)=Conn(PS1)。由于Conn(PSi).flag标记不为0,报文PSi被调度至Conn(PSi).sensor,即Conn[PS1].sensor,说明报文PSi也被调度至引擎Am。
证毕。
定理4同一五元组的所有UDP报文,被调度至同一检测引擎。
证明:标记该组UDP五元组为U,由证明3可以得出,该五元组的第一个报文PU1被调度前,由于Conn(PU1).flag标记为0,PU1被调度至当前负载最轻的引擎Am,且标记Conn(PU1).sensor=Am。
令PUi表示为五元组U的第i个报文(i≠1),由于PUi和PU1的五元组相同,则Conn(PUi)=Conn(PU1)。由于Conn(PUi).flag标记不为0,报文PUi被调度至Conn(PUi).sensor,即Conn(PU1).sensor,说明报文PUi也被调度至引擎Am。
证毕。
构造如图3所示的实验拓扑,其中,交换机与路由器、交换机与负载均衡服务器,以及交换机与Sensor B之间链路最高传输速率为10 Gbit/s,其余链路最高传输速率为1 Gbit/s。为突出测试并行入侵检测方法的性能,不宜采用性能超强的服务器用作检测引擎,主机硬件配置见表1。
表1 主机硬件配置
图3 实验拓扑
其中,SensorA1-A4、SensorB及负载均衡服务器均安装CentOS 7.0 64 bit操作系统,SensorA1-A4运行Snort3.0,仅保留单连接攻击规则文件;Sensor B运行Snort3.0,仅保留多连接攻击规则文件;负载均衡服务器监控SensorA1-A4的负载,运行算法1完成流量调度。
攻击区共8台主机,每台主机安装3个虚拟机,每个虚拟机分配1 GB内存,并轮询使用10个IP地址;被攻击区共4台服务器,每台服务器安装3个虚拟机,并分别提供20个TCP服务和UDP服务,以上可以构造出57 600个不同的五元组,足以确保实验质量。
攻击区安装Blade IDS Informer软件[15],产生各种网络攻击行为,加上正常网络流量,通过TcpReplay软件重放实现包含以上攻击行为的高速网络流量[16]。
定义5NIDS检测结果评价指标F-Measure。
参阅文献[17],F-Measure(F)指标能全面准确评估NIDS的检测结果,公式定义如下:
(5)
式中:R表示召回率;P表示查准率。
P=TP/(TP+FP)
(6)
R=TP/(TP+FN)
(7)
定义6NIDS检测时延。
假设NIDS采集完网络流量的时间为t1,NIDS最终检测完成的时间t2,则NIDS的检测时延Δt有如下公式:
Δt=t2-t1
(8)
定义7NIDS丢包率
假设NIDS检测过程中丢失的报文数量为lp,待检网络流量总报文数量为ap,则丢包率L(loss_rate)有如下公式:
L=lp/ap
(9)
表2 不同Max_num取值下的实验结果
本实验包含多连接攻击检测以及单连接攻击检测, SensorA1-A4、SensorB以及负载均衡服务器全部工作。将本文方法与文献[9]提出的多检测引擎监测的动态负载均衡算法,文献[10]提出的基于能力与负载的数据分割算法,文献[11]提出的动态层次负载均衡算法,文献[12]提出的预测负载均衡方法,文献[13]提出的基于“最小PPS”的动态流量调度策略,统一采用4.1描述的实验拓扑及环境,做不同方法的实验对比。
图4 单连接攻击检测的
图5 多连接攻击检测的
分析原因,本文方法中多连接攻击检测子系统采用单检测引擎,没有攻击证据的丢失。同时,为提高检查效率,检测引擎快速扫描报文首部,并只匹配多连接攻击规则库。而其他方法没有区分单连接攻击和多连接攻击,统一采用多检测引擎并行检测,造成多连接攻击的流量被调度至不同检测引擎,而检测引擎间又缺少互相通信获取全局信息的机制,导致攻击证据的丢失,检测结果相对本文方法较差。
图6 平均检测时延
图7 平均丢包率
实验表明,本文方法在高速网络环境下,具有更高的实用性和稳定性。
本文提出的基于攻击分类的高性能并行入侵检测方法,分为单连接攻击检测系统和多连接攻击检测系统,有效地解决了攻击证据保持及负载均衡问题。实验结果表明,相比其他并行入侵检测方法,本文方法在单连接攻击及多连接攻击检测中均表现优秀,F-Measure值提升显著,检测时延和丢包率也有一定降低。通过优化模式匹配算法及规则连设计方法,提升单个检测引擎的检测性能,从而提升并行NIDS的整体检测性能,是作者今后的研究重点。