降噪的需求
自从引入了态势感知设备,处于阴暗面下的网络威胁也终于暴露在阳光下,但是这又引入了一个新的问题,就是面对海量的数据,人工根本无法分析全部数据,而且大部分数据存在误报的情况,这是因为大部分态势感知采用的规则引擎是使用正则匹配的手法。本文采用的是在此基础上新的引入了随机森林算法,并且通过逻辑回归模型优化了随机森林算法进行二次筛选的过程
随机森林算法概述&缺陷
1)信息、熵以及信息增益的概念
这三个基本概念是决策树的根本,是决策树利用特征来分类时,确定特征选取顺序的依据。理解了它们,决策树你也就了解了大概。
引用香农的话来说,信息是用来消除随机不确定性的东西。当然这句话虽然经典,但是还是很难去搞明白这种东西到底是个什么样,可能在不同的地方来说,指的东西又不一样。对于机器学习中的决策树而言,如果带分类的事物集合可以划分为多个类别当中,则某个类(xi)的信息可以定义如下:
I(x)用来表示随机变量的信息,p(xi)指是当xi发生时的概率。
熵是用来度量不确定性的,当熵越大,X=xi的不确定性越大,反之越小。对于机器学习中的分类问题而言,熵越大即这个类别的不确定性更大,反之越小。
信息增益在决策树算法中是用来选择特征的指标,信息增益越大,则这个特征的选择性越好。
2)决策树
决策树是一种树形结构,其中每个内部节点表示一个属性上的测试,每个分支代表一个测试输出,每个叶节点代表一种类别。常见的决策树算法有C4.5、ID3和CART。
3)集成学习
集成学习通过建立几个模型组合的来解决单一预测问题。它的工作原理是生成多个分类器/模型,各自独立地学习和作出预测。这些预测最后结合成单预测,因此优于任何一个单分类的做出预测。
初始随机算法demo
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report
# 使用列表存储 SQL 查询和对应的标签(0: 正常SQL, 1: SQL注入攻击)
payloads = [
("SELECT * FROM users WHERE username = 'admin' AND password = 'password'", 0),
("SELECT * FROM users WHERE username = '' OR '1'='1'", 1), # 确保这是 SQL 注入示例
("SELECT id, name FROM employees WHERE id = 100", 0),
("DROP TABLE users; --", 1),
("INSERT INTO users (username, password) VALUES ('test', '1234')", 0),
("SELECT * FROM products WHERE price < 100 OR 1=1", 1),
("SELECT * FROM orders WHERE order_id = 105", 0),
("SELECT * FROM users WHERE email = 'test@example.com'", 0),
("DELETE FROM users WHERE user_id = 101; --", 1),
("SELECT * FROM customers WHERE customer_id = 200 OR 1=1", 1),
("SELECT * FROM products WHERE name = 'test' OR 'x'='x'", 1) # 添加更多典型的 SQL 注入
]
# 将列表转换为DataFrame
df = pd.DataFrame(payloads, columns=['query', 'label'])
# 分割数据集
X = df['query']
y = df['label']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 特征提取
vectorizer = CountVectorizer()
X_train_vec = vectorizer.fit_transform(X_train)
X_test_vec = vectorizer.transform(X_test)
# 训练模型
model = RandomForestClassifier()
model.fit(X_train_vec, y_train)
# 预测
y_pred = model.predict(X_test_vec)
# 输出评估结果
print(classification_report(y_test, y_pred))
# 实时监测示例
def detect_sql_injection(query):
query_vec = vectorizer.transform([query])
prediction = model.predict(query_vec)
if prediction[0] == 1:
return "Potential SQL Injection Detected!"
else:
return "Normal SQL Query."
# 测试监测函数
print(detect_sql_injection("SELECT * FROM users WHERE username = 'admin' "))
print(detect_sql_injection("/global/product_index/smart_home_en/retail-products/e3330/+b(f.html?f.substring(0,300):"))
其实随机森林算法在后续的样本引入中已经有不错的表现成果,但是会存在一个缺陷
SELECT * FROM users WHERE username = 'admin'
对于我们的实例语句,随机森林的决策树,会将'admin',中的‘’,标记为一个注入,这样造成的问题,就是经过迭代后,含有单引号的都会判定为注入,会对我们的算法后续产生污染,所以得纠正这个问题
二分类问题和鲁棒性
为什么会选择随机森林算法,因为,判断数据来源是否是误报,是一个二分类的问题,就存在0或者1的结果,而且他是一个集成式机器学习模型,说明核是通过对数据集进行随机采样,训练出多个独立的模型,然后将这些模型的预测结果进行平均或投票,从而生成最终预测,提高了模型的稳定性。然后是提到的鲁棒性,也就是模型的抗干扰能力
例如测试语句的长度,在测试的过程中,发现同样具有鲁棒性的dbscan算法,在面临相同长度的语句时,在面临非均匀密度、高维数据集以及参数选择问题时,鲁棒性较差
图片:
从二分类的问题上,还有一种绕不开的模型,线性模型,其中核心的思想是输入特征与输出之间的关系可以用线性组合表示。从线性模型中采用了逻辑回归模型,因为它通过逻辑函数将线性回归的输出映射到0到1之间,从而得到一个概率值。逻辑回归的主要思想是寻找一条最优的分界线,适合处理线性可分的数据。而且逻辑回归模型可以通过特征权重进行决定。但是逻辑回归模型对于高纬,抽象的数据的鲁棒性较差。在实验中可以发现,逻辑回归模型在应对,url转码,orceal sql,等其他非常规的数据中,在训练的数据集中的非常规数据较少的情况下,呈现了高误报率,反观随机森林,在数据集不那么充足的情况下,依然可以准确识别出攻击
所以由此我们可以设计一个新的机制,可以将随机森林算法的输出模型,作为逻辑回归的输入模型,而且通过权重的配比,实现随机森林在某些语句上的缺失。
抗干扰能力:
算法改进
这里给出部分代码来进行结果的展示
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.metrics.pairwise import cosine_similarity
import matplotlib.pyplot as plt
import numpy as np
# 使用列表存储 SQL 查询和对应的标签(0: 正常SQL, 1: SQL注入攻击)
payloads = [
]
df = pd.DataFrame(payloads, columns=['query', 'label'])
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(df['query']).toarray()
y = df['label']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 训练随机森林模型
rf_model = RandomForestClassifier()
rf_model.fit(X_train, y_train)
# 获取随机森林的预测概率
rf_probabilities_train = rf_model.predict_proba(X_train)[:, 1]
rf_probabilities_test = rf_model.predict_proba(X_test)[:, 1]
# 将随机森林的预测概率作为新特征
X_train_rf = X_train.copy()
X_test_rf = X_test.copy()
X_train_rf = np.column_stack((X_train_rf, rf_probabilities_train))
X_test_rf = np.column_stack((X_test_rf, rf_probabilities_test))
# 训练逻辑回归模型
lr_model = LogisticRegression()
lr_model.fit(X_train_rf, y_train)
# 评估模型
y_pred = lr_model.predict(X_test_rf)
accuracy = accuracy_score(y_test, y_pred)
print(f"Model Accuracy: {accuracy:.2f}")
# 定义检测函数
def detect_sql_injection(query, threshold=0.5):
query_vec = vectorizer.transform([query]).toarray()
rf_prob = rf_model.predict_proba(query_vec)[0][1]
query_vec_with_rf = np.column_stack((query_vec, rf_prob))
probabilities = lr_model.predict_proba(query_vec_with_rf)[0]
normal_prob = probabilities[0]
injection_prob = probabilities[1]
# 计算新查询与已知查询的余弦相似度
similarities = cosine_similarity(query_vec, X).flatten()
# 筛选相似度大于0.3的值
similar_indices = [i for i, sim in enumerate(similarities) if sim > 0.45]
similar_queries = df.iloc[similar_indices]
最终结果,实现了95%的识别准确率