对于入侵检测的研究,须要大量有效的实验数据。数据能够经过抓包工具来采集,如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')