千家信息网

Web安全与机器学习(KNN篇)

发表于:2024-11-14 作者:千家信息网编辑
千家信息网最后更新 2024年11月14日,sklearn之knn近邻算法近邻算法检测异常操作数据来源:http://www.schonlau.net/网页中的Masquerading User Data。其中包含50个用户的操作日志,每个日志
千家信息网最后更新 2024年11月14日Web安全与机器学习(KNN篇)

sklearn之knn近邻算法

近邻算法检测异常操作

数据来源:http://www.schonlau.net/网页中的Masquerading User Data。其中包含50个用户的操作日志,每个日志包含1500条操作命令,前面5000条是正常的操作,后面的10000条日志中随即包含有异常操作。具体参考《Web安全机器学习入门》

基础知识

本来想自己写的,但是网上资料太多,就没必要写了。看下其他大佬写过的就行了:

  • https://blog.csdn.net/zgcr654321/article/details/85219121
  • https://www.jianshu.com/p/3dcb39de04aa

这两个看了,基本上就没啥问题了

编程实现

Step 1:随便选择一个user日志,里面每行代表一个命令。每150个命令弄成一个操作序列,保存在列表之中

def load_user(filename):    most_cmd = []    mini_cmd = []    cmd_list = []    cmd_seq = []    # 获取操作序列    with open(filename, 'r', encoding="utf-8") as f:        cmd = f.readline()        temp = []        cnt = 0        while(cmd):            cmd_list.append(cmd.strip('\n'))            temp.append(cmd.strip('\n'))            cnt = cnt + 1            if(cnt == 150):  #  这里不按照书上的分,我这里按照150个命令为一个序列,刚好和标签对上号,因为标签只有100个值                cmd_seq.append(temp)                cnt = 0                temp = []            cmd = f.readline()

Step 2:然后将user日志中所有的命令进行统计,统计出它们最频繁的50个命令,以及最不频繁的50个命令

# 获取最频繁的前50个命令,获取最不频繁的前50个命令fdist = sorted(FreqDist(cmd_list).items(),key = operator.itemgetter(1), reverse = True) # 按照出现频率排序most_cmd = [ item[0] for item in fdist[:50]]mini_cmd = [ item[0] for item in fdist[-50:]]

Step 3:特征化。在 Step 1 的操作序列上,我们按一个操作系列为单元,①统计其中不重复的命令个数、②最频繁的10个命令、③最不频繁的10个命令

user_feature = [] for cmd_list in user_cmd_list:    # 获取每个序列不重复命令的个数    seq_len = len(set(cmd_list))    # 将每个序列按照出现频率由高到低的排列命令    fdist = sorted(FreqDist(cmd_list).items(), key=operator.itemgetter(1), reverse=True)    seq_freq = [item[0] for item in fdist]    # 获取最频繁和最不频繁的前10个命令    f2 = seq_freq[:10]    f3 = seq_freq[-10:]

Step 4:因为KNN只能接收数值类型输入。在 Step 4 中,②和③都是字符串的命令,我们需要将其标量化。标量化的方式:统计最频繁使用的50个命令和最不频繁使用的50个命令计算重合程度

# 计算重合度f2 = len(set(f2) & set(user_max_freq))f3 = len(set(f3) & set(user_min_freq))# 合并特征:①每个序列不重复的命令个数;②每个序列最频繁的前10个命令和user中最频繁的50个命令重合度;# ③每个序列最不频繁的前10个命令和user中最不频繁的前50个命令重合度;user_feature.append([seq_len, f2, f3])

python3完整代码如下

from nltk.probability import FreqDist  # 统计命令出现频率import operatorfrom sklearn.neighbors import KNeighborsClassifierimport numpy as npdef load_user(filename):        most_cmd = []        mini_cmd = []        cmd_list = []        cmd_seq = []        # 获取操作序列        with open(filename, 'r', encoding="utf-8") as f:                cmd = f.readline()                temp = []                cnt = 0                while(cmd):                        cmd_list.append(cmd.strip('\n'))                        temp.append(cmd.strip('\n'))                        cnt = cnt + 1                        if(cnt == 150):  #  这里不按照书上的分,我这里按照150个命令为一个序列,刚好和标签对上号,因为标签只有100个值                                cmd_seq.append(temp)                                cnt = 0                                temp = []                        cmd = f.readline()        # 获取最频繁的前50个命令,获取最不频繁的前50个命令        fdist = sorted(FreqDist(cmd_list).items(),key = operator.itemgetter(1), reverse = True) # 按照出现频率排序        most_cmd = [ item[0] for item in fdist[:50]]        mini_cmd = [ item[0] for item in fdist[-50:]]        return cmd_seq, most_cmd, mini_cmddef get_user_feature(user_cmd_list, user_max_freq, user_min_freq):        user_feature = []         for cmd_list in user_cmd_list:                # 获取每个序列不重复命令的个数                seq_len = len(set(cmd_list))                # 将每个序列按照出现频率由高到低的排列命令                fdist = sorted(FreqDist(cmd_list).items(), key=operator.itemgetter(1), reverse=True)                seq_freq = [item[0] for item in fdist]                # 获取最频繁和最不频繁的前10个命令                f2 = seq_freq[:10]                f3 = seq_freq[-10:]                # 计算重合度                f2 = len(set(f2) & set(user_max_freq))                f3 = len(set(f3) & set(user_min_freq))                # 合并特征:①每个序列不重复的命令个数;②每个序列最频繁的前10个命令和user中最频繁的50个命令重合度;③每个序列最不频繁的前10个命令和user中最不频繁的前50个命令重合度;                user_feature.append([seq_len, f2, f3])        return user_featuredef get_labels(filename):  # 获取第三列的标签        labels = []        cnt = 0        with open(filename, 'r', encoding="utf-8") as f:                temp = f.readline().strip('\n')                while(temp):                        labels.append(int(temp[4]))                         cnt += 1                        temp = f.readline().strip('\n')            return labelsif __name__ == "__main__":        user_cmd_list, user_max_freq, user_min_freq = load_user('user.txt')        user_feature = get_user_feature(user_cmd_list, user_max_freq, user_min_freq)        labels = get_labels('labels.txt')        # 切割数据集:训练集和测试集        x_train = user_feature[0:70]        y_train = labels[0:70]        x_test = user_feature[70:]        y_test = labels[70:]        # 训练数据        neight = KNeighborsClassifier(n_neighbors=3)        neight.fit(x_train, y_train)        # 预测        y_predict = neight.predict(x_test)        # 计算得分        score = np.mean(y_test == y_predict) * 100        print(score)  # 90.0

最终获得90%的正确率。

总结

①获取最频繁的前50个命令,书上的方式获取的并不是最频繁的前50个。在这里我改了下代码。②标签和数据对不上号,命令共有15000个,标签只有100个。书上的做法是每100个为一个操作序列,也就是有150个操作序列,然后在标签出再前面增加了50个标签。我的代码是将150个命令作为一个序列,这样下来刚好合适。

最后推荐下个人博客:https://unihac.github.io/

0