◆孟 平 龍華秋
(五邑大學智能制造學部 廣東 529020)
如今互聯網的發展速度和規模的擴張十分迅猛,IT技術、硬件產品和軟件產品的迭代更新非常迅速。互聯網+的時代,如此迅速的發展給我們的生活帶來了巨大的便利,同時也帶來了眾多的安全隱患。在大多數人眼中,互聯網上的安全問題,大多都是數據泄露,以及其他相關問題,這些問題影響的大多都是企業,造成的損失也基本是經濟上的損失。然而近年來發生的多起工業控制系統相關的安全問題,充分證明了攻擊者完全可以通過互聯網威脅到人們的現實生活,比如近期國外發生的工控系統入侵事件導致的他國全國范圍大部分地區停電的事件。當下互聯網的安全問題,已經被國家高中重視,網絡安全事關國家安全。
利用機器學習中的監督學習相關算法訓練好的模型,在實際中應用時,可以快速對一個新提取的樣本做判斷,判斷其是否惡意。比以往通過特征碼等其他判斷方式,少了查詢“特征碼集合”和比對的操作,其判斷速度上要遠快于傳統方式。良好的訓練集和合適的算法及相應的參數,可使訓練出來的模型具有很好的泛化性能。
計算機網絡具有多層協議,在其七層模型(物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層、應用層)中,物理層和數據鏈路層太過底層,會話層、表示層和應用層涉及的協議眾多不適合作為用于進行判斷其是否惡意的基礎。在網絡層上可以開始不考慮具體的數據傳輸的實現,而傳輸層TCP和UDP協議是上層協議的基礎且僅為實現連續和離散的傳輸方式。因此在本次研究中,判斷流量是否惡意便是基于網絡層和傳輸層的數據報文。
在整個機器學習入侵檢測中,我們需要有“流量探針”為我們捕獲流量,而捕獲的數據報文要經過“特征提取”,提取的特征會組成一個“樣本”,樣本將會是我們直接用于訓練模型和模型判斷的目標。在本次研究中,由于服務器性能等問題,為了方便,我們直接使用KDD 99 比賽中提供的五百萬現成的樣本,作為訓練模型和模型評估的數據集合。在整個系統中將分為三個部分:模型訓練、樣本采集和模型判斷。
圖1為系統流程圖。
如流程圖中所示,整個系統中有三個部分相對獨立:模型訓練、檢測判斷、樣本采集。本系統涉及機器學習的內容,要保證模型訓練、樣本采集和檢測判斷的部分的最終樣本的維度特征的一致性,才能保證模型的使用。因本課題中,對樣本的判斷可以看作是分類,即是否具有攻擊性和可能的攻擊類別,因此在機器學習模型算法的選擇上,我們將選擇分類器相關的算法。

圖1 系統流程圖
以下將對模型訓練階段的內容進行講解:
在本次研究課題中,我們采用的是機器學習中監督學習的邏輯斯諦回歸算法(Logistic Regression)。需要注意的是,邏輯斯諦回歸算法并不是回歸模型相關的算法,而是用于分類的分類器算法。
2.1.1 算法原理
邏輯斯蒂回歸(Logistic Regression),是一種分類算法,其算法原理如下:

不同類的x對應z的值為0或者1,單位階躍函數由于函數性質不可導不連續,所以引入sigmoid函數:

圖2函數圖

所以令:

得到:

化成對數形式:

y/(1-y) 代表了樣本作為正例的可能性,1-y是反例。
所以y=概率p(y=1|x)
1-y=概率p(y=0|x)
所以上式又可化為:

解得:

將這2個等式化成一個等式:

對上式連乘,然后取對數,進行極大似然估計:

最大化上式相等于最小化:

這是一個凸函數,可以使用梯度下降或者牛頓迭代(割線法)來求最優解。
梯度下降的迭代式為:
因為要往增高的方向,所以是+號,代表梯度的正方向。
2.1.2 邏輯斯蒂回歸——多分類擴展
邏輯斯蒂回歸是二分類器,本系統是多分類器,所以采用OVR的方式將二分類器的方式擴展到多分類器,OVR訓練多個分類器,每一個分類器將某一類別的視為正樣本,其他視為負樣本,訓練出n個后,然后輸出每個樣本對應每個類別的概率,取最大的概率作為最終的輸出結果。

為了方便,我們在模型訓練階段直接使用了KDD 99比賽的數據集,以縮減前期數據采集的時間。該數據集采集自美國軍方網絡,其樣本的特征基于計算機網絡的網絡層和傳輸層的,但在其提供的特征上做了適當的選擇和特征的向量化,使其更加適用于本課題的研究。
具體特征內容如下:
(1)duration:TCP以3次握手建立到FIN/ACK連接結束為止的時間;
(2)protocol type:協議類型;
(3)Service:網絡服務類型;
(4)flag:連接正常或錯誤;
(5)src_bytes:源主機到目標主機數據字節數;
(6)dst_bytes:目標主機到源主機數據字節數;
(7)land:若連接來自或送達同一個主機則為1,否則為0;
(8)wrong_fragment:錯誤分段數量;
(9)urgent:加急包個數;
(10)count:與當前連接具有相同的目標主機的連接數;
(11)srv_count:與當前連接具有相同服務的連接數;
(12)serror_rate:在與當前連接具有相同目標主機的連接中,出現“SYN”錯誤的連接的百分比;
(13)srv_serror_rate:在與當前連接具有相同服務的連接中,出現“SYN”錯誤的連接的百分比;
(14)rerror_rate:在與當前連接具有相同目標主機的連接中,出現“REJ”錯誤的連接的百分比;
(15)srv_rerror_rate:在與當前連接具有相同服務的連接中,出現“REJ”錯誤的連接的百分比;
(16)same_srv_rate:在與當前連接具有相同目標主機的連接中,與當前連接具有相同服務的連接的百分比;
(17)diff_srv_rate:在與當前連接具有相同目標主機的連接中,與當前連接具有不同服務的連接的百分比;
(18)srv_diff_host_rate:在與當前連接具有相同服務的連接中,與當前連接具有不同目標主機的連接的百分比;
(19)dst_host_count:與當前連接具有相同目標主機的連接數;
(20)dst_host_srv_count:與當前連接具有相同目標主機相同服務的連接數;
(21)dst_host_same_srv_rate:與當前連接具有相同目標主機相同服務的連接所占的百分比;
(22)dst_host_diff_srv_rate:與當前連接具有相同目標主機不同服務的連接所占的百分比;
(23)dst_host_same_src_port_rate:與當前連接具有相同目標主機相同源端口的連接所占的百分比;
(24)dst_host_srv_diff_host_rate:與當前連接具有相同目標主機相同服務的連接中,與當前連接具有不同源主機的連接所占的百分比;
(25)dst_host_serror_rate:與當前連接具有相同目標主機的連接中,出現SYN錯誤的連接所占的百分比;
(26)dst_host_srv_serror_rate:與當前連接具有相同目標主機相同服務的連接中,出現SYN錯誤的連接所占的百分比;
(27)dst_host_rerror_rate:與當前連接具有相同目標主機的連接中,出現REJ錯誤的連接所占的百分比;
(28)dst_host_srv_rerror_rate:與當前連接具有相同目標主機相同服務的連接中,出現REJ錯誤的連接所占的百分比。
def ReadData(path):
data=open(path).readlines()
data=np.array([i.split(',') for i in data])
data[:, -1]= [i.replace(' ', '').replace('.', '') for i in data[:, -1]]
data_r=np.zeros(shape=data.shape)
data_r[:,0]=[float(i) for i in data[:,0]]
for i in range(4,40):
data_r[:, i]= [float(j) for j in data[:, i]]
protocol_type={k:i for i,k in enumerate(set(data[:,1]))}
service={k:i for i,k in enumerate(set(data[:,2]))}
flag={k:i for i,k in enumerate(set(data[:,3]))}
label={k:i for i,k in enumerate(set(data[:,-1]))}
print(protocol_type)
print(service)
print(flag)
print(label)
data_r[:, 1]= [protocol_type[j]for j in data[:, 1]]
data_r[:, 2]= [service[j]for j in data[:, 2]]
data_r[:, 3]= [flag[j]for j in data[:, 3]]
data_r[:, -1]= [label[j]for j in data[:, -1]]
data_r=np.c_[data_r[:,0:9],data_r[:,22:42]]
weight={}
for j in range(len(label)):
weight[j]=len(data)-len([i for i in data_r if i[-1]==j])
return data_r,weight
def Classify(feature,weight):
lr=LogisticRegression()
X_train, X_test, y_train, y_test = train_test_split(feature[:,:-1],feature[:,-1], test_size = 0.3, random_state = 42)
w=[weight[i]for i in y_train]
d = [weight[i]for i in y_test]
lr.fit(X_train,y_train,sample_weight=w)
print(str(lr.score(X_test,y_test,sample_weight=d)))
joblib.dump(lr, 'kdd99lr')
def train():
feature,weight=ReadData(r'kddcup.data.corrected')
Classify(feature,weight)
train()

圖3 數據采集功能
其中DONE表明該表明該樣本已經過模型檢測判斷等處理。
圖4內容為已訓練好的模型對樣本采集器中樣本的檢測結果。

圖4 檢測結果

表1 模型性能評估表

phf 0.00 0.00 0.00 1 ipsweep 0.98 0.20 0.33 3709 smurf 1.00 1.00 1.00 842033 pod 0.00 0.00 0.00 72 rootkit 0.00 0.00 0.00 3 neptune 0.99 1.00 0.99 321807 warezmaster 0.00 0.00 0.00 5 multihop 0.00 0.00 0.00 1 nmap 0.88 0.09 0.17 733 teardrop 1.00 0.99 0.99 279 back 0.00 0.00 0.00 664 spy 0.00 0.00 0.00 1 ftp_write 0.00 0.00 0.00 4 loadmodule 0.00 0.00 0.00 3 land 0.50 0.20 0.29 10 buffer_overflow 0.00 0.00 0.00 10 warezclient 0.00 0.00 0.00 303 guess_passwd 0.00 0.00 0.00 13 portsweep 0.25 0.00 0.00 3079 Imap 0.00 0.00 0.00 1 perl 0.00 0.00 0.00 1 multihop 0.98 1.00 0.99 291976 Micro-avg 0.99 0.99 0.99 1469530 Macro-avg 0.33 0.23 0.25 1469530 Weighted-avg 0.99 0.99 0.99 1469530
本文詳細介紹了基于Python的機器學習入侵檢測系統的設計與實現。項目總共有三大功能需要實現:模型訓練、檢測判斷、樣本采集。在本項目中,我們直接使用KDD 99 比賽中提供的五百萬現成的樣本,作為訓練模型和模型評估的數據集,使用邏輯斯蒂回歸算法對流量樣本進行訓練,從大量的流量數據集合中找到惡意樣本。通過在實際環境進行的大量網絡流量測試,與流量樣本的測試,驗證了該入侵檢測系統的實用性。