對於入侵檢測的研究,須要大量有效的實驗數據。數據能夠經過抓包工具來採集,如Unix下的Tcpdump,Windows下的libdump,或者專用的軟件snort捕捉數據包,生成鏈接記錄做爲數據源。本文使用的是基於數據挖掘的入侵檢測技術研究中使用的KDDCup99的網絡入侵檢測數據集。git
原文連接 https://blog.gongyan.me/2017/04/kdd-cup99/ 轉載請註明,有問題歡迎聯繫我gongyanc@outlook.comgithub
該數據集是從一個模擬的美國空軍局域網上採集來的9個星期的網絡鏈接數據,分紅具備標識的訓練數據和未加標識的測試數據。測試數據和訓練數據有着不一樣的機率分佈,測試數據包含了一些未出如今訓練數據中的攻擊類型,這使得入侵檢測更具備現實性。
在訓練數據集中包含了1種正常的標識類型normal和22種訓練攻擊類型,如表1-1所示。另外有14種攻擊僅出如今測試數據集中。算法
表1-1 KDDCup99入侵檢測實驗數據的標識類型sql
標識類型 | 含義 | 具體分類標識 |
---|---|---|
Normal | 正常記錄 | Normal |
DOS | 拒絕服務攻擊 | back、land、neptune、pod、smurf、teardrop |
Probing | 監視和其餘探測活動 | ipsweep、nmap、portsweep、satan |
R2L | 來自遠程機器的非法訪問 | ftp_write、guess_passwd、imap、multihop、phf、spy、warezclient、warezmaster |
U2R | 普通用戶對本地超級用戶特權的非法訪問 | buffer_overflow、loadmodule、perl、rootkit |
數據特徵:KDDCup99訓練數據集中每一個鏈接記錄包含了41個固定的特徵屬性和1個類標識,如圖1-1所示,標識用來表示該條鏈接記錄是正常的,或是某個具體的攻擊類型。在41個固定的特徵屬性中,9個特徵屬性爲離散(symbolic)型,其餘均爲連續(continuous)型。apache
聚類算法中要使用計算距離的方法對數據進行聚類,而鏈接記錄的固定特徵屬性中有兩種類型的數值:離散型和連續型。對於連續型特徵屬性,各屬性的度量方法不同。通常而言,所用的度量單位越小,變量可能的值域就越大,這樣對聚類結果的影響也越大,即在計算數據間距離時對聚類的影響越大,甚至會出現「大數」吃「小數」的現象。所以爲了不對度量單位選擇的依賴,消除因爲屬性度量的差別對聚類產生的影響,須要對屬性值進行標準化。對於離散型特徵屬性本文中並不做標準化處理,而是放在聚類算法中計算距離時處理。因此數據標準化是針對連續型特徵屬性的。設訓練數據集有n條網絡鏈接記錄,每一個記錄中有22個連續型屬性向量記做Xij(1≤i≤n,11≤j≤41)。對Xij數據預處理分爲兩步:數值標準化和數值歸一化。網絡
表1-4以2秒時間窗口計算的流量特徵app
特徵名 | 描述 | 類型 |
---|---|---|
count | 過去的2秒內與當前鏈接有着相同的目的地址的鏈接 | 連續 |
serror_rate | 出現SYN錯誤的鏈接次數 | 連續 |
rerror_rate | 出現REJ錯誤的鏈接次數 | 連續 |
same_srv_rate | 創建相同服務的鏈接次數 | 連續 |
diff_srv_rate | 創建不一樣服務的鏈接次數 | 連續 |
srv_count | 過去2秒時間內出現和當前鏈接服務相同的鏈接次數 | 連續 |
srv_serror_rate | 出現SYN錯誤的鏈接次數 | 連續 |
srv_rerror_rate | 出現REJ錯誤的鏈接次數 | 連續 |
srv_diff_host_rate | 鏈接不相同主機的次數 | 連續 |
設 $X'_{ij}$ 爲 $X_{ij}$ 數值標準化後的值。ide
$X'_{ij} = \frac{ X_{ij}-AVG_j }{ STAD_j }$工具
$AVG_j = \frac{ 1 }{ n }(X_{1j}+X_{2j}+...+X_{nj})$oop
$STAD_j = \frac{ 1 }{ n }(\lvert X_{1j}-AVG_j \lvert +\lvert X_{2j}-AVG_j \lvert +...+ \lvert X_{nj}-AVG_j \lvert )$
設 $X'' _{ij}$爲 $X_{ij}$歸一化後的值。
$ X''_{ij} = \frac{ X'_{ij}-X _{min} } { X_{max} - X_{min} } $
$X_{min} = min{ X'_{ij} }$
$X_{max} = max{ X'_{ij} }$
其中下標變量1<=i<=n, 11<=j<=41
數值歸一化處理過程及歸一化後數據實例如圖2-1
0.0 | 2.6104176374e-07 | 0.00105713002195 |
0.0 | 0.0 | 0.0 |
0.0 | 0.0 | 0.0 |
0.0 | 0.0 | 0.0 |
0.0156555772994 | 0.0 | 0.0 |
0.0 | 0.0 | 1.0 |
0.0 | 0.0352941176471 | 0.0352941176471 |
1.0 | 0.0 | 0.11 |
0.0 | 0.0 | 0.0 |
0.0 | 1 |
KDD99數據集總共由500萬條記錄構成,它還提供一個10%的訓練子集和測試子集。樣本類別分佈表以下:
標籤 | 類別 | 訓練集(10%) | 測試集(Corrected) |
---|---|---|---|
1 | NORMAL | 97278 | 60593 |
2 | PROBE | 4107 | 4166 |
3 | ipsweep | 1247 | 306 |
4 | mscan | / | 1053 |
5 | nmap | 231 | 84 |
6 | portsweep | 1040 | 354 |
7 | saint | / | 736 |
8 | satan | 1589 | 1633 |
9 | DOS | 391458 | 229853 |
10 | apache2 | / | 794 |
11 | back | 2203 | 1098 |
12 | land | 21 | 9 |
13 | mailbomb | / | 5000 |
14 | neptune | 107201 | 58001 |
15 | pod | 264 | 87 |
16 | processtable | / | 759 |
17 | smurf | 280790 | 164091 |
18 | teardrop | 979 | 12 |
19 | udpstorm | / | 2 |
20 | U2R | 52 | 228 |
21 | buffer_overflow | 30 | 22 |
22 | httptunnel | / | 158 |
23 | loadmodule | 9 | 2 |
24 | perl | 3 | 2 |
25 | ps | / | 16 |
26 | rootkit | 10 | 13 |
27 | sqlattack | / | 2 |
28 | xterm | / | 13 |
29 | R2L | 1126 | 16189 |
30 | ftp_write | 8 | 3 |
31 | guess_passwd | 53 | 4367 |
32 | imap | 12 | 1 |
33 | multihop | 7 | 18 |
34 | named | / | 17 |
35 | phf | 4 | 2 |
36 | sendmail | / | 17 |
37 | snmpgetattack | / | 7741 |
38 | snmpguess | / | 2406 |
39 | spy | 2 | / |
40 | warezclient | 1020 | / |
41 | warezmaster | 20 | 1602 |
42 | worm | / | 2 |
43 | xlock | / | 9 |
44 | xsnoop | / | 4 |
如上表,同DARPA98同樣,KDD99將攻擊類型分爲4類,而後又細分爲39小類,每一類表明一種攻擊類型,類型名被標記在訓練數據集每一行記錄的最後一項。
從表中能夠看出,訓練集中共出現了22個攻擊類型,而剩下的17種只在測試集中出現,這樣設計的目的是檢驗分類器模型的泛化能力,對未知攻擊類型的檢測能力是評價入侵檢測。
kNN算法的指導思想是「近朱者赤,近墨者黑」,由你的鄰居來推斷出你的類別。計算步驟以下:
什麼是合適的距離衡量?距離越近應該意味着這兩個點屬於一個分類的可能性越大。距離衡量包括歐式距離、夾角餘弦等。本實驗使用歐式(Euclidean)距離。
投票決定:少數服從多數,近鄰中哪一個類別的點最多就分爲該類。
加權投票法:根據距離的遠近,對近鄰的投票進行加權,距離越近則權重越大(權重爲距離平方的倒數)
k過小,分類結果易受噪聲點影響;k太大,近鄰中又可能包含太多的其它類別的點。(對距離加權,能夠下降k值設定的影響)
k值一般是採用交叉檢驗來肯定(以k=1爲基準)
經驗規則:k通常低於訓練樣本數的平方根
投票法沒有考慮近鄰的距離的遠近,距離更近的近鄰也許更應該決定最終的分類,因此加權投票法更恰當一些。
高維度對距離衡量的影響:衆所周知當變量數越多,歐式距離的區分能力就越差。
變量值域對距離的影響:值域越大的變量經常會在距離計算中佔據主導做用,所以應先對變進行標準化。
# coding=utf-8 from __future__ import division import numpy as np import matplotlib.pyplot as plt def classify(input_vct, data_set): data_set_size = data_set.shape[0] diff_mat = np.tile(input_vct, (data_set_size, 1)) - data_set # 擴充input_vct到與data_set同型並相減 sq_diff_mat = diff_mat**2 # 矩陣中每一個元素都平方 distance = sq_diff_mat.sum(axis=1)**0.5 # 每行相加求和並開平方根 return distance.min(axis=0) # 返回最小距離 def file2mat(test_filename, para_num): """ 將表格存入矩陣,test_filename爲表格路徑,para_num爲存入矩陣的列數 返回目標矩陣,和矩陣每一行數據的類別 """ fr = open(test_filename) lines = fr.readlines() line_nums = len(lines) result_mat = np.zeros((line_nums, para_num)) # 建立line_nums行,para_num列的矩陣 class_label = [] for i in range(line_nums): line = lines[i].strip() item_mat = line.split(',') result_mat[i, :] = item_mat[0: para_num] class_label.append(item_mat[-1]) # 表格中最後一列正常1異常2的分類存入class_label fr.close() return result_mat, class_label def roc(data_set): normal = 0 data_set_size = data_set.shape[1] roc_rate = np.zeros((2, data_set_size)) for i in range(data_set_size): if data_set[2][i] == 1: normal += 1 abnormal = data_set_size - normal max_dis = data_set[1].max() for j in range(1000): threshold = max_dis / 1000 * j normal1 = 0 abnormal1 = 0 for k in range(data_set_size): if data_set[1][k] > threshold and data_set[2][k] == 1: normal1 += 1 if data_set[1][k] > threshold and data_set[2][k] == 2: abnormal1 += 1 roc_rate[0][j] = normal1 / normal # 閾值以上正常點/全體正常的點 roc_rate[1][j] = abnormal1 / abnormal # 閾值以上異常點/全體異常點 return roc_rate def test(training_filename, test_filename): training_mat, training_label = file2mat(training_filename, 32) test_mat, test_label = file2mat(test_filename, 32) test_size = test_mat.shape[0] result = np.zeros((test_size, 3)) for i in range(test_size): result[i] = i + 1, classify(test_mat[i], training_mat), test_label[i] # 序號, 最小歐氏距離, 測試集數據類別 result = np.transpose(result) # 矩陣轉置 plt.figure(1) plt.scatter(result[0], result[1], c=result[2], edgecolors='None', s=1, alpha=1) # 圖1 散點圖:橫軸爲序號,縱軸爲最小歐氏距離,點中心顏色根據測試集數據類別而定, 點外圍無顏色,點大小爲最小1,灰度爲最大1 roc_rate = roc(result) plt.figure(2) plt.scatter(roc_rate[0], roc_rate[1], edgecolors='None', s=1, alpha=1) # 圖2 ROC曲線, 橫軸誤報率,即閾值以上正常點/全體正常的點;縱軸檢測率,即閾值以上異常點/全體異常點 plt.show() if __name__ == "__main__": test('training.csv', 'test.csv')