目录
选题意义背景
入侵检测技术的发展可以追溯到20世纪80年代,Anderson首次提出了入侵检测的概念,Dennig随后提出了通用入侵检测模型,为后续研究奠定了理论基础。进入90年代,Heberlein等人开发了第一个基于网络的入侵检测系统,标志着网络入侵检测技术的正式兴起。然而,随着网络规模的扩大和攻击技术的演进,传统的入侵检测方法逐渐暴露出诸多不足。

传统的端口扫描和深度包检测(DPI)等方法在面对加密流量和复杂多变的攻击手段时表现不佳,误判代价高和数据漂移问题也是当前入侵检测技术面临的重要挑战。在实际应用中,过高的误报率会导致安全人员疲于应对,降低系统的实用性;而网络环境的动态变化和攻击手段的不断更新,则会导致模型性能随时间推移而下降。

针对上述问题,本研究提出了基于多级特征融合的流量分类方法和基于记忆模块的流量异常检测方法,旨在通过创新的特征提取和模型设计,提高入侵检测系统的检测精度、适应性和实用性。这对于增强网络安全防御能力,保障关键信息基础设施安全,具有重要的理论意义和实际应用价值。
数据集
攻击流量数据
为了更加全面地评估算法在面对各类攻击时的性能,本研究还构造了部分攻击流量数据:
-
数据来源:通过网络安全测试工具生成各类攻击流量,包括应用层攻击、暴力破解、DoS攻击和端口扫描等。
-
攻击类型:
- 应用层攻击:包括HTTP洪水攻击、SQL注入攻击、跨站脚本攻击等。
- 暴力破解攻击:针对SSH、FTP等服务的暴力破解尝试。
- DoS攻击:包括TCP SYN洪水、UDP洪水等拒绝服务攻击。
- 端口扫描:包括TCP连接扫描、SYN扫描、FIN扫描等。
-
数据合并:将构造的攻击流量与智能电网真实流量数据进行合并,生成包含正常流量和攻击流量的混合数据集,用于算法训练和测试。
数据分割
在模型训练和评估过程中,采用以下数据分割策略:
-
训练集与测试集划分:将数据集按照6:4的比例划分为训练集和测试集。训练集用于模型的训练和参数优化,测试集用于评估模型的最终性能。
-
交叉验证:采用5折交叉验证的方法对模型进行评估,以确保模型性能的稳定性和可靠性。
-
时间分割:对于研究数据漂移问题的实验,采用时间分割的方法,使用早期数据进行训练,使用后期数据进行测试,以模拟数据分布随时间变化的场景。
数据预处理
在将数据输入模型之前,需要进行一系列预处理操作:
-
特征提取:根据研究内容,从原始网络流量中提取统计特征和行为特征。统计特征包括数据包大小分布、传输速率、会话持续时间等;行为特征包括流量的时序模式、连接状态变化等。
-
特征标准化:使用Z-score标准化方法对特征进行标准化处理,将不同尺度的特征转换到同一尺度,避免特征之间的量级差异对模型训练产生影响。
-
特征选择:通过相关性分析、主成分分析(PCA)等方法进行特征选择,去除冗余特征和噪声特征,提高模型的训练效率和泛化能力。
-
数据增强:对于类别不平衡的问题,采用过采样、欠采样或生成对抗网络(GAN)等方法进行数据增强,提高少数类样本的代表性。
通过以上数据集的获取和处理过程,本研究构建了全面、多样的实验数据集,为算法的训练、验证和测试提供了坚实的数据基础。这些数据集涵盖了不同场景、不同类型的网络流量和攻击行为,能够全面评估算法的性能和适应性。
功能模块介绍
本研究的功能模块主要包括三个核心部分:多级特征融合的流量分类模块、基于记忆模块的流量异常检测模块以及面向智能电网的流量入侵检测系统。下面对每个模块的技术思路、流程和实现过程进行详细介绍。

多级特征融合的流量分类
主要针对全量数据场景,通过提取和融合不同层次的特征,实现对网络流量所属终端类型的准确分类:针对传统方法特征挖掘不充分的问题,提出多级特征构造与融合的思路,将流量分为流级和段级两个层次进行特征提取,通过自动编码器和聚类算法实现特征的深度融合和表征学习。功能流程:
-
流量分段处理:
- 将原始网络流按照时间窗口(段长300秒)划分为多个流段
- 每个流段作为基本处理单元,保留流的时序特性
-
多级特征提取:
- 段级统计特征:对每个流段提取数据包大小分布、传输速率、会话持续时间等统计特征
- 段级行为特征:捕获流段中数据包的时序模式、连接状态变化等行为特征
- 流级统计特征:对整个网络流提取全局统计特征,如总数据包数、总字节数等

-
行为特征编码:
-
使用自动编码器(AE)对段级行为特征进行编码,学习行为特征的低维表示
-
自动编码器结构包含输入层、隐藏层和输出层,通过重构误差优化模型参数
-
编码器部分输出的隐藏层表示作为行为特征的嵌入向量

-
-
段级特征融合:
- 将段级统计特征与行为嵌入向量进行拼接
- 使用K-Means聚类算法对融合后的特征进行聚类,得到段级特征的聚类中心
- 对聚类结果进行独热编码处理,转换为可用于分类的特征向量
-
流量类型识别:
- 将流级统计特征与段级特征融合结果进行合并
- 使用梯度提升决策树(GBDT)作为分类器,对流量所属的终端类型进行识别
- 输出分类结果,标记流量所属的终端类型
基于记忆模块的流量异常检测
该模块主要针对元数据场景,通过特征扩展和记忆模块机制,实现对网络流量异常行为的有效检测:针对元数据特征不足的问题,提出多角度的特征扩展方法,引入地理位置信息,利用流间时序信息,挖掘统计特征和突变特征,设计基于记忆模块的异常检测模型,通过维护正常行为模式来检测异常

功能流程:
-
特征扩展:
- 滑动窗口统计特征:使用时间滑动窗口计算流量的统计特征,如平均值、标准差等
- 地理位置突变特征(GLMF):基于IP地址的地理位置信息,检测地理位置的异常变化
- 攻击规则特征(ARF):基于已知攻击模式的规则库,提取流量的规则匹配特征
- 基线规则特征(BRF):基于正常流量的基线模型,提取偏离基线的特征
-
记忆模块设计:设计两个存储器M1和M2,分别存储最近的正常样本和历史正常样本, 存储器结构包括样本特征、访问频率和时间戳等信息,内存寻址采用曼哈顿距离计算最近邻,查找与当前样本最相似的记忆样本
-
记忆模块更新机制:M1存储器采用FIFO算法进行更新,保持最近的正常样本,M2存储器根据异常评分进行排序,优先保留评分较低的正常样本,定期将M1中的样本合并到M2中,更新历史记忆
-
模型更新条件:计算当前批次数据的异常比例, 根据异常比例和数据漂移判定阈值,决定是否更新模型,当异常比例超过阈值时,触发模型更新,重新训练自动编码器
-
流式自学习异常检测:使用自动编码器对扩展后的特征进行编码和解码,计算重构误差,结合记忆模块的距离度量,得到综合异常评分,根据异常评分判断流量是否异常,输出检测结果
面向智能电网的流量入侵检测系统
该系统将前两个模块的算法整合到一个完整的应用系统中,结合Suricata入侵检测引擎和ELK数据分析框架,实现了面向智能电网的流量入侵检测功能,采用分布式部署架构,将系统分为agent、server和state三个节点, 结合规则检测和异常检测两种方法,提高检测的准确性和全面性,利用ELK框架实现数据的存储、分析和可视化,便于管理和决策功能流程:
-
流量采集模块:
- 使用Suricata流量引擎对网络流量进行捕获
- 通过pkt2flow工具将数据包切分为网络流
- 基于dpkt库提取流级全量数据和元数据
- 将采集的数据通过Logstash传输到Elasticsearch数据库
-
流量检测模块:
- 规则检测:部署Suricata规则检测引擎,通过内置规则进行入侵检测
- 流量分类:部署多级特征融合的流量分类算法,识别终端类型
- 异常检测:部署基于记忆模块的流量异常检测算法,检测异常行为
- 将检测结果写入Elasticsearch数据库,生成相应的索引
-
流量可视化模块:
- 基于Kibana工具构建可视化界面
- 设计终端分析页面,展示终端分布、流量强度等信息
- 设计流量检测页面,展示异常告警、攻击类型分布等信息
- 提供时间趋势分析、源/目标IP统计等功能,支持攻击溯源
算法理论
本研究涉及的核心算法理论主要包括多级特征融合的流量分类算法和基于记忆模块的流量异常检测算法。下面对这些算法的理论基础和工作原理进行详细介绍。
多级特征融合的流量分类
多级特征融合的流量分类算法主要基于深度学习和机器学习的理论,通过提取和融合不同层次的特征,实现对网络流量的准确分类。
网络流量具有时序特性,为了更好地捕获这种特性,算法将网络流按照时间窗口划分为多个流段。这种分段处理的理论基础是:
- 时序数据分段理论:将长时序数据划分为短时序片段,可以更好地捕获局部特征和模式变化。
- 统计特征理论:通过计算均值、方差、最大值、最小值等统计量,可以有效描述数据的分布特征。
- 行为特征理论:网络流量的行为特征反映了通信双方的交互模式,对于识别流量类型具有重要意义。

算法提取的特征包括段级统计特征、段级行为特征和流级统计特征,这些特征从不同角度描述了网络流量的特性,为后续的分类提供了丰富的信息。
聚类算法是一种无监督学习方法,用于将相似的数据样本聚为一类。本算法使用K-Means聚类算法进行段级特征融合,其理论基础包括:
- 距离度量理论:K-Means使用欧氏距离作为样本间相似度的度量标准。
- 中心优化理论:通过迭代更新聚类中心,使类内距离最小,类间距离最大。
- 特征融合理论:通过聚类可以将原始特征转换为聚类中心的分布特征,实现特征的融合和降维。
K-Means算法的迭代过程包括两个关键步骤:
- 分配步骤:计算每个样本到各个聚类中心的距离,将样本分配到距离最近的聚类。
- 更新步骤:重新计算每个聚类的中心,作为该聚类所有样本的均值。
梯度提升决策树(GBDT)是一种集成学习算法,通过组合多个决策树来提高预测性能。其理论基础包括:
- 集成学习理论:通过组合多个弱学习器,可以构建强学习器,提高泛化能力。
- 梯度提升理论:基于梯度下降的思想,每次迭代都构建一个新的决策树,来拟合当前模型的残差。
- CART树理论:GBDT使用分类回归树(CART)作为基学习器,CART树是一种二叉树结构,可以同时处理分类和回归问题。
GBDT的训练过程包括以下步骤:
- 初始化一个简单模型(通常是常数模型)作为初始预测。
- 计算当前模型的残差,即真实值与预测值之间的差异。
- 构建一棵新的决策树,拟合当前残差。
- 更新模型,将新决策树的预测结果以一定权重添加到当前模型中。
- 重复步骤2-4,直到达到预设的迭代次数或模型性能不再提升。
在本算法中,GBDT用于融合流级特征和段级特征,实现对网络流量所属终端类型的分类。
基于记忆模块的流量异常检测算法
基于记忆模块的流量异常检测算法主要基于异常检测和记忆增强学习的理论,通过特征扩展和记忆机制,实现对网络流量异常的有效检测,特征扩展是解决元数据特征不足问题的重要方法,其理论基础包括:
- 特征工程理论:通过构造和提取更有信息量的特征,可以提高模型的性能。
- 多源数据融合理论:结合不同来源的信息(如地理位置数据),可以获得更全面的特征表示。
- 时序特征提取理论:利用时间序列的动态特性,可以捕获数据的时序模式和异常变化。

记忆模块是算法的核心创新点,其理论基础包括:
-
记忆增强学习理论:通过外部记忆模块辅助神经网络,可以增强模型的记忆能力和适应性。
-
最近邻检索理论:通过计算样本间的距离,查找最相似的记忆样本,用于异常判断。
-
经验学习理论:通过不断积累和更新记忆,模型可以从经验中学习,适应环境变化。
异常检测是识别与正常模式显著不同的数据点或模式的过程,其理论基础包括: -
单类分类理论:假设正常数据服从某种分布,异常数据是分布外的样本。
-
重构误差理论:正常数据可以被较好地重构,而异常数据的重构误差较大。
-
密度估计理论:异常数据通常位于数据分布的低密度区域。
数据漂移是指数据分布随时间变化的现象,自适应理论用于解决这一问题:
- 概念漂移检测理论:通过监控数据分布的变化,检测概念漂移的发生。
- 在线学习理论:模型可以在流式数据环境中不断学习和更新,适应新的数据分布。
- 模型更新策略理论:通过合理的更新策略,在保持模型稳定性的同时提高适应性。
核心代码
以下是本研究中最具代表性的三个核心代码片段,每个片段都包含详细的文字说明和代码实现。
多级特征融合的流量分类
多级特征融合的流量分类算法的核心部分,包括自动编码器模型定义、特征提取和融合、以及分类器训练。该部分代码是算法的核心,负责将原始网络流量数据转换为特征向量,并通过多级融合和分类器实现终端类型的识别。代码结构清晰,分为数据处理、模型定义和模型训练三个主要部分,使用PyTorch框架实现深度学习模型,使用scikit-learn库实现传统机器学习算法。
import torch
import torch.nn as nn
import torch.optim as optim
from sklearn.cluster import KMeans
from sklearn.ensemble import GradientBoostingClassifier
import numpy as np
import pandas as pd
# 自动编码器模型定义
class Autoencoder(nn.Module):
def __init__(self, input_dim, hidden_dim):
super(Autoencoder, self).__init__()
# 编码器部分
self.encoder = nn.Sequential(
nn.Linear(input_dim, hidden_dim * 2),
nn.ReLU(),
nn.Linear(hidden_dim * 2, hidden_dim)
)
# 解码器部分
self.decoder = nn.Sequential(
nn.Linear(hidden_dim, hidden_dim * 2),
nn.ReLU(),
nn.Linear(hidden_dim * 2, input_dim),
nn.Sigmoid()
)
def forward(self, x):
# 前向传播
encoded = self.encoder(x)
decoded = self.decoder(encoded)
return encoded, decoded
# 特征提取函数
def extract_features(flow_data, segment_length=300):
segments = []
# 将流量按时间窗口分段
for i in range(0, len(flow_data), segment_length):
segment = flow_data[i:i+segment_length]
if len(segment) > 0:
# 提取段级统计特征
stat_features = {
'avg_pkt_size': np.mean(segment['pkt_size']),
'std_pkt_size': np.std(segment['pkt_size']),
'max_pkt_size': np.max(segment['pkt_size']),
'min_pkt_size': np.min(segment['pkt_size']),
'pkt_count': len(segment),
'avg_inter_arrival': np.mean(np.diff(segment['timestamp']))
}
# 提取段级行为特征
behavior_features = extract_behavior_features(segment)
segment_features = {**stat_features, **behavior_features}
segments.append(segment_features)
# 提取流级统计特征
flow_features = {
'total_pkts': len(flow_data),
'total_bytes': np.sum(flow_data['pkt_size']),
'duration': flow_data['timestamp'].iloc[-1] - flow_data['timestamp'].iloc[0]
}
return segments, flow_features
# 特征融合和分类函数
def classify_flow(flow_data, ae_model, kmeans_model, gbdt_model):
# 提取特征
segments, flow_features = extract_features(flow_data)
# 将特征转换为向量
segment_stat_vectors = np.array([[s['avg_pkt_size'], s['std_pkt_size'], s['max_pkt_size'],
s['min_pkt_size'], s['pkt_count'], s['avg_inter_arrival']]
for s in segments])
segment_behavior_vectors = np.array([[s['feature1'], s['feature2'], s['feature3']]
for s in segments])
# 使用自动编码器编码行为特征
ae_model.eval()
with torch.no_grad():
behavior_tensor = torch.tensor(segment_behavior_vectors, dtype=torch.float32)
behavior_embeddings, _ = ae_model(behavior_tensor)
behavior_embeddings = behavior_embeddings.numpy()
# 融合段级特征
segment_features = np.hstack((segment_stat_vectors, behavior_embeddings))
# 使用K-Means聚类
cluster_labels = kmeans_model.predict(segment_features)
# 生成独热编码特征
one_hot = np.zeros((1, kmeans_model.n_clusters))
for label in cluster_labels:
one_hot[0, label] += 1
one_hot = one_hot / len(cluster_labels) # 归一化
# 融合流级特征和段级特征
flow_vector = np.array([flow_features['total_pkts'], flow_features['total_bytes'],
flow_features['duration']])
final_features = np.hstack((flow_vector, one_hot.flatten()))
# 使用GBDT分类
prediction = gbdt_model.predict([final_features])[0]
return prediction
# 模型训练函数
def train_models(flow_datasets, labels, ae_hidden_dim=64, n_clusters=15):
# 准备训练数据
all_segment_features = []
all_flow_features = []
for flow_data in flow_datasets:
segments, flow_features = extract_features(flow_data)
# 提取所有段级特征用于训练自动编码器和K-Means
for s in segments:
stat_vector = np.array([s['avg_pkt_size'], s['std_pkt_size'], s['max_pkt_size'],
s['min_pkt_size'], s['pkt_count'], s['avg_inter_arrival']])
behavior_vector = np.array([s['feature1'], s['feature2'], s['feature3']])
all_segment_features.append((stat_vector, behavior_vector))
# 提取流级特征用于训练GBDT
flow_vector = np.array([flow_features['total_pkts'], flow_features['total_bytes'],
flow_features['duration']])
all_flow_features.append(flow_vector)
# 训练自动编码器
behavior_vectors = np.array([b for _, b in all_segment_features])
ae_input_dim = behavior_vectors.shape[1]
ae_model = Autoencoder(ae_input_dim, ae_hidden_dim)
criterion = nn.MSELoss()
optimizer = optim.Adam(ae_model.parameters(), lr=0.001)
behavior_tensor = torch.tensor(behavior_vectors, dtype=torch.float32)
for epoch in range(100):
ae_model.train()
optimizer.zero_grad()
_, decoded = ae_model(behavior_tensor)
loss = criterion(decoded, behavior_tensor)
loss.backward()
optimizer.step()
if (epoch + 1) % 10 == 0:
print(f'Autoencoder Epoch [{epoch+1}/100], Loss: {loss.item():.4f}')
# 使用自动编码器生成嵌入向量并训练K-Means
ae_model.eval()
with torch.no_grad():
behavior_embeddings, _ = ae_model(behavior_tensor)
behavior_embeddings = behavior_embeddings.numpy()
stat_vectors = np.array([s for s, _ in all_segment_features])
combined_features = np.hstack((stat_vectors, behavior_embeddings))
kmeans_model = KMeans(n_clusters=n_clusters, random_state=42)
kmeans_model.fit(combined_features)
# 为每个流量生成最终特征并训练GBDT
X_train = []
for i, flow_data in enumerate(flow_datasets):
segments, _ = extract_features(flow_data)
# 提取段级特征
segment_stat_vectors = np.array([[s['avg_pkt_size'], s['std_pkt_size'], s['max_pkt_size'],
s['min_pkt_size'], s['pkt_count'], s['avg_inter_arrival']]
for s in segments])
segment_behavior_vectors = np.array([[s['feature1'], s['feature2'], s['feature3']]
for s in segments])
# 生成行为嵌入向量
with torch.no_grad():
behavior_tensor = torch.tensor(segment_behavior_vectors, dtype=torch.float32)
behavior_embeddings, _ = ae_model(behavior_tensor)
behavior_embeddings = behavior_embeddings.numpy()
# 融合段级特征并聚类
segment_features = np.hstack((segment_stat_vectors, behavior_embeddings))
cluster_labels = kmeans_model.predict(segment_features)
# 生成独热编码特征
one_hot = np.zeros(n_clusters)
for label in cluster_labels:
one_hot[label] += 1
one_hot = one_hot / len(cluster_labels)
# 融合流级特征和段级特征
final_features = np.hstack((all_flow_features[i], one_hot))
X_train.append(final_features)
# 训练GBDT分类器
gbdt_model = GradientBoostingClassifier(n_estimators=100, learning_rate=0.1,
max_depth=3, random_state=42)
gbdt_model.fit(X_train, labels)
return ae_model, kmeans_model, gbdt_model
基于记忆模块的流量异常检测
基于记忆模块的流量异常检测算法的核心部分,包括特征扩展函数、记忆模块类和异常检测主函数。该部分代码是算法的核心创新点,通过特征扩展解决元数据特征不足的问题,通过记忆模块机制解决数据漂移问题。代码设计了两个记忆模块(M1和M2),分别存储最近和历史的正常样本,并实现了相应的更新和检索机制。异常检测结合了自动编码器的重构误差和记忆模块的距离度量,提高了检测的准确性。
import numpy as np
import pandas as pd
from collections import deque
import torch
import torch.nn as nn
import torch.optim as optim
from geolite2 import geolite2
import time
# 特征扩展函数
def extend_features(meta_data):
extended_features = []
# 滑动窗口统计特征
window_size = 10
for i in range(len(meta_data)):
window_start = max(0, i - window_size + 1)
window_data = meta_data[window_start:i+1]
# 计算窗口统计特征
window_features = {
'window_avg_duration': np.mean(window_data['duration']),
'window_std_duration': np.std(window_data['duration']),
'window_avg_bytes': np.mean(window_data['bytes']),
'window_std_bytes': np.std(window_data['bytes']),
'window_avg_packets': np.mean(window_data['packets'])
}
# 地理位置突变特征(GLMF)
geo_reader = geolite2.reader()
src_ip = meta_data.iloc[i]['src_ip']
dst_ip = meta_data.iloc[i]['dst_ip']
# 获取地理位置信息
src_geo = geo_reader.get(src_ip) or {}
dst_geo = geo_reader.get(dst_ip) or {}
src_country = src_geo.get('country', {}).get('iso_code', 'Unknown')
dst_country = dst_geo.get('country', {}).get('iso_code', 'Unknown')
# 检查是否有地理位置突变
geo_sudden_change = 0
if i > 0:
prev_src_ip = meta_data.iloc[i-1]['src_ip']
prev_src_geo = geo_reader.get(prev_src_ip) or {}
prev_src_country = prev_src_geo.get('country', {}).get('iso_code', 'Unknown')
if prev_src_country != src_country:
geo_sudden_change = 1
# 攻击规则特征(ARF)
attack_rules = [
lambda x: x['src_port'] in [21, 22, 23, 3389], # 常见服务端口
lambda x: x['dst_port'] in [21, 22, 23, 3389],
lambda x: x['duration'] < 0.01, # 极短连接
lambda x: x['packets'] == 1 # 单包连接
]
arf_features = {f'rule_{i}': int(rule(meta_data.iloc[i])) for i, rule in enumerate(attack_rules)}
# 基线规则特征(BRF)
# 基于历史数据计算基线
if i >= 100:
historical_data = meta_data[:i]
duration_mean = np.mean(historical_data['duration'])
duration_std = np.std(historical_data['duration'])
brf_features = {
'duration_zscore': (meta_data.iloc[i]['duration'] - duration_mean) / (duration_std + 1e-10),
'bytes_zscore': (meta_data.iloc[i]['bytes'] - np.mean(historical_data['bytes'])) / (np.std(historical_data['bytes']) + 1e-10),
'packets_zscore': (meta_data.iloc[i]['packets'] - np.mean(historical_data['packets'])) / (np.std(historical_data['packets']) + 1e-10)
}
else:
brf_features = {
'duration_zscore': 0,
'bytes_zscore': 0,
'packets_zscore': 0
}
# 合并所有特征
sample_features = {
**meta_data.iloc[i].to_dict(),
**window_features,
'geo_sudden_change': geo_sudden_change,
**arf_features,
**brf_features
}
extended_features.append(sample_features)
geolite2.close()
return pd.DataFrame(extended_features)
# 记忆模块类
class MemoryModule:
def __init__(self, m1_size=1000, m2_size=5000):
# M1存储最近的正常样本
self.M1 = deque(maxlen=m1_size)
# M2存储历史正常样本
self.M2 = []
self.M2_max_size = m2_size
def add_to_M1(self, sample):
"""添加样本到M1"""
self.M1.append(sample)
def update_M2(self, anomaly_scores):
"""根据异常评分更新M2"""
# 将M1中的样本合并到M2
new_samples = list(self.M1)
self.M1.clear()
# 为新样本分配异常评分
scored_samples = list(zip(new_samples, anomaly_scores))
# 添加到M2并按异常评分排序
self.M2.extend(scored_samples)
self.M2.sort(key=lambda x: x[1])
# 保持M2大小
if len(self.M2) > self.M2_max_size:
self.M2 = self.M2[:self.M2_max_size]
def find_nearest(self, sample, k=5):
"""查找最相似的k个记忆样本"""
all_samples = list(self.M1) + [s for s, _ in self.M2]
if not all_samples:
return None, float('inf')
# 计算曼哈顿距离
distances = []
for mem_sample in all_samples:
# 只使用数值特征计算距离
numeric_sample = np.array([v for v in sample.values() if isinstance(v, (int, float))])
numeric_mem = np.array([v for v in mem_sample.values() if isinstance(v, (int, float))])
# 确保特征维度一致
min_len = min(len(numeric_sample), len(numeric_mem))
dist = np.sum(np.abs(numeric_sample[:min_len] - numeric_mem[:min_len]))
distances.append((mem_sample, dist))
# 排序并返回最近的k个样本
distances.sort(key=lambda x: x[1])
nearest_samples = distances[:k]
# 返回平均距离作为异常指标
avg_distance = np.mean([d for _, d in nearest_samples])
return nearest_samples, avg_distance
# 自动编码器模型(与前面相同)
class Autoencoder(nn.Module):
def __init__(self, input_dim, hidden_dim):
super(Autoencoder, self).__init__()
self.encoder = nn.Sequential(
nn.Linear(input_dim, hidden_dim * 2),
nn.ReLU(),
nn.Linear(hidden_dim * 2, hidden_dim)
)
self.decoder = nn.Sequential(
nn.Linear(hidden_dim, hidden_dim * 2),
nn.ReLU(),
nn.Linear(hidden_dim * 2, input_dim),
nn.Sigmoid()
)
def forward(self, x):
encoded = self.encoder(x)
decoded = self.decoder(encoded)
return encoded, decoded
# 异常检测主函数
def anomaly_detection(meta_data, model=None, memory_module=None, retrain_threshold=0.1):
# 扩展特征
extended_data = extend_features(meta_data)
# 准备特征向量
feature_columns = ['duration', 'bytes', 'packets', 'window_avg_duration', 'window_std_duration',
'window_avg_bytes', 'window_std_bytes', 'window_avg_packets', 'geo_sudden_change',
'rule_0', 'rule_1', 'rule_2', 'rule_3', 'duration_zscore', 'bytes_zscore', 'packets_zscore']
feature_vectors = extended_data[feature_columns].values
# 标准化
feature_vectors = (feature_vectors - np.mean(feature_vectors, axis=0)) / (np.std(feature_vectors, axis=0) + 1e-10)
# 初始化模型和记忆模块(如果没有提供)
if model is None:
input_dim = feature_vectors.shape[1]
model = Autoencoder(input_dim, 64)
# 初始训练(使用前100个样本作为正常样本)
if len(feature_vectors) > 100:
train_data = torch.tensor(feature_vectors[:100], dtype=torch.float32)
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
for epoch in range(50):
model.train()
optimizer.zero_grad()
_, decoded = model(train_data)
loss = criterion(decoded, train_data)
loss.backward()
optimizer.step()
if memory_module is None:
memory_module = MemoryModule()
# 初始化记忆模块(添加前100个样本作为正常样本)
if len(extended_data) > 100:
for i in range(100):
memory_module.add_to_M1(extended_data.iloc[i].to_dict())
# 异常检测
model.eval()
anomaly_scores = []
is_anomalies = []
with torch.no_grad():
for i, features in enumerate(feature_vectors):
# 转换为tensor
feature_tensor = torch.tensor(features, dtype=torch.float32).unsqueeze(0)
# 使用自动编码器计算重构误差
_, decoded = model(feature_tensor)
reconstruction_error = torch.mean(torch.abs(decoded - feature_tensor)).item()
# 使用记忆模块计算距离
sample_dict = extended_data.iloc[i].to_dict()
_, memory_distance = memory_module.find_nearest(sample_dict)
# 计算综合异常评分(加权平均)
# 这里使用简单的加权平均,可以根据实际情况调整权重
anomaly_score = 0.5 * reconstruction_error + 0.5 * memory_distance
anomaly_scores.append(anomaly_score)
# 判断是否异常(这里使用简单的阈值,可以根据实际情况调整)
threshold = 0.1 # 示例阈值
is_anomaly = anomaly_score > threshold
is_anomalies.append(int(is_anomaly))
# 如果不是异常,添加到记忆模块
if not is_anomaly:
memory_module.add_to_M1(sample_dict)
# 更新记忆模块M2
if len(anomaly_scores) > 0:
memory_module.update_M2(anomaly_scores)
# 检查是否需要重新训练模型(数据漂移检测)
anomaly_ratio = np.mean(is_anomalies)
if anomaly_ratio > retrain_threshold:
# 重新训练模型
# 选择异常评分较低的样本作为正常样本
normal_indices = np.argsort(anomaly_scores)[:int(len(anomaly_scores) * 0.8)]
normal_features = feature_vectors[normal_indices]
if len(normal_features) > 0:
train_data = torch.tensor(normal_features, dtype=torch.float32)
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
for epoch in range(50):
model.train()
optimizer.zero_grad()
_, decoded = model(train_data)
loss = criterion(decoded, train_data)
loss.backward()
optimizer.step()
# 返回结果
results = extended_data.copy()
results['anomaly_score'] = anomaly_scores
results['is_anomaly'] = is_anomalies
return results, model, memory_module
智能电网流量入侵检测
面向智能电网的流量入侵检测系统的部署和数据通路配置。该部分代码负责将前面实现的算法整合到实际系统中,结合Suricata入侵检测引擎和ELK框架,实现数据采集、处理、分析和可视化的全流程。代码包括Suricata配置、Logstash数据通路设置、算法部署和结果写入等功能模块。通过这段代码,可以将理论算法转化为实际可用的系统,应用于智能电网的安全监控。
import os
import json
import time
import subprocess
import threading
import pandas as pd
from elasticsearch import Elasticsearch
from datetime import datetime
# Suricata配置
class SuricataConfig:
def __init__(self, config_dir='/etc/suricata', eve_log_path='/var/log/suricata/eve.json'):
self.config_dir = config_dir
self.eve_log_path = eve_log_path
def update_config(self):
"""更新Suricata配置文件"""
# 这里可以添加更新Suricata配置的代码
# 例如修改suricata.yaml文件,添加自定义规则等
print(f"Updating Suricata configuration in {self.config_dir}")
def start_suricata(self):
"""启动Suricata服务"""
print(f"Starting Suricata service...")
try:
# 使用subprocess启动Suricata
# 实际部署时可能需要使用systemctl或service命令
subprocess.run(['suricata', '-c', os.path.join(self.config_dir, 'suricata.yaml'), '-i', 'eth0'],
check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print("Suricata started successfully")
except subprocess.CalledProcessError as e:
print(f"Failed to start Suricata: {e}")
def create_lua_script(self):
"""创建Lua脚本来提取自定义流量信息"""
lua_script = '''
-- 自定义Lua脚本,用于提取包级元数据
function init (args)
local needs = {}
needs["type"] = "packet"
return needs
end
function setup (args)
local fname = "custom_packet_info.json"
file = assert(io.open(fname, "a"))
return {}
end
function log(args)
local timestring = SCLogTime()
local timestamp = SCGetPacketTimestamp()
-- 提取包五元组信息
local tuple = SCPacketTuple()
-- 构建JSON输出
local output = {
timestamp = timestamp,
timestring = timestring,
src_ip = tuple[1],
dst_ip = tuple[2],
src_port = tuple[3],
dst_port = tuple[4],
proto = tuple[5]
}
-- 写入JSON数据
file:write(json.encode(output) .. "\n")
file:flush()
end
function deinit (args)
file:close()
end
'''
# 保存Lua脚本
lua_script_path = os.path.join(self.config_dir, 'scripts', 'custom_packet_info.lua')
os.makedirs(os.path.dirname(lua_script_path), exist_ok=True)
with open(lua_script_path, 'w') as f:
f.write(lua_script)
print(f"Created Lua script at {lua_script_path}")
# Logstash配置
class LogstashConfig:
def __init__(self, elastic_host='localhost:9200'):
self.elastic_host = elastic_host
def create_suricata_config(self):
"""创建Suricata告警数据的Logstash配置"""
config_content = '''
input {
file {
path => "/var/log/suricata/eve.json"
codec => json
type => "SuricataAlert"
}
}
output {
elasticsearch {
hosts => ["http://{}:9200"]
index => "suricata"
codec => json
}
}
'''.format(self.elastic_host.split(':')[0])
config_path = '/etc/logstash/conf.d/suricata.conf'
os.makedirs(os.path.dirname(config_path), exist_ok=True)
with open(config_path, 'w') as f:
f.write(config_content)
print(f"Created Suricata Logstash config at {config_path}")
def create_packet_config(self):
"""创建包级元数据的Logstash配置"""
config_content = '''
input {
file {
path => "/etc/suricata/scripts/custom_packet_info.json"
codec => json
type => "PacketInfo"
}
}
output {
elasticsearch {
hosts => ["http://{}:9200"]
index => "packetinfo"
codec => json
}
}
'''.format(self.elastic_host.split(':')[0])
config_path = '/etc/logstash/conf.d/packet_info.conf'
with open(config_path, 'w') as f:
f.write(config_content)
print(f"Created Packet Info Logstash config at {config_path}")
def start_logstash(self):
"""启动Logstash服务"""
print("Starting Logstash service...")
try:
# 实际部署时可能需要使用nohup或systemctl
subprocess.run(['nohup', 'logstash', '-f', '/etc/logstash/conf.d/'],
check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print("Logstash started successfully")
except subprocess.CalledProcessError as e:
print(f"Failed to start Logstash: {e}")
# 算法部署和结果写入
class AlgorithmDeployer:
def __init__(self, elastic_client):
self.elastic_client = elastic_client
# 这里可以加载前面定义的模型
self.ae_model = None
self.kmeans_model = None
self.gbdt_model = None
self.memory_module = None
def load_models(self):
"""加载训练好的模型"""
print("Loading trained models...")
# 这里应该从文件加载保存的模型
# 示例:
# self.ae_model = torch.load('models/autoencoder.pth')
# self.kmeans_model = joblib.load('models/kmeans.pkl')
# self.gbdt_model = joblib.load('models/gbdt.pkl')
print("Models loaded successfully")
def process_flow_data(self):
"""处理流数据并运行算法"""
print("Processing flow data...")
# 这里应该实现从Elasticsearch读取数据的逻辑
# 然后使用前面定义的算法处理数据
# 示例伪代码:
# 1. 从Elasticsearch读取flow数据
# 2. 使用classify_flow函数进行流量分类
# 3. 将结果写回Elasticsearch
# 模拟处理结果
terminal_types = ['配变终端', '低压抄表集中器', '负荷管理终端']
results = []
for i in range(100): # 模拟处理100个流
result = {
'flow_id': f'flow_{i}',
'timestamp': datetime.now().isoformat(),
'terminal_type': terminal_types[i % 3],
'confidence': 0.9 + (i % 10) * 0.01
}
results.append(result)
# 将结果写入Elasticsearch
self.write_to_elasticsearch(results, 'terminaltype')
def process_metadata(self):
"""处理元数据并运行异常检测算法"""
print("Processing metadata...")
# 这里应该实现从Elasticsearch读取元数据的逻辑
# 然后使用前面定义的异常检测算法处理数据
# 示例伪代码:
# 1. 从Elasticsearch读取metadata
# 2. 使用anomaly_detection函数进行异常检测
# 3. 将结果写回Elasticsearch
# 模拟处理结果
results = []
for i in range(100): # 模拟处理100个元数据样本
result = {
'metadata_id': f'meta_{i}',
'timestamp': datetime.now().isoformat(),
'anomaly_score': 0.1 + (i % 20) * 0.01,
'is_anomaly': 1 if i % 20 > 15 else 0
}
results.append(result)
# 将结果写入Elasticsearch
self.write_to_elasticsearch(results, 'anomalydetection')
def write_to_elasticsearch(self, data, index_name):
"""将数据写入Elasticsearch"""
for item in data:
try:
self.elastic_client.index(index=index_name, body=item)
except Exception as e:
print(f"Error writing to Elasticsearch: {e}")
def start_processing(self):
"""启动处理线程"""
# 启动流量分类处理线程
flow_thread = threading.Thread(target=self.process_flow_data)
flow_thread.daemon = True
flow_thread.start()
# 启动异常检测处理线程
meta_thread = threading.Thread(target=self.process_metadata)
meta_thread.daemon = True
meta_thread.start()
# 主线程保持运行
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print("Stopping processing threads...")
# 系统部署主函数
def deploy_system():
# 初始化Elasticsearch客户端
es_client = Elasticsearch(['http://localhost:9200'])
# 配置Suricata
suricata_config = SuricataConfig()
suricata_config.update_config()
suricata_config.create_lua_script()
# suricata_config.start_suricata() # 实际部署时取消注释
# 配置Logstash
logstash_config = LogstashConfig()
logstash_config.create_suricata_config()
logstash_config.create_packet_config()
# logstash_config.start_logstash() # 实际部署时取消注释
# 部署算法
algorithm_deployer = AlgorithmDeployer(es_client)
algorithm_deployer.load_models()
# 启动处理
print("Starting system processing...")
algorithm_deployer.start_processing()
if __name__ == "__main__":
deploy_system()
重难点和创新点
本研究的主要重难点和创新点如下:
多级特征融合的流量分类方法
-
多级特征构造方法:本研究提出了段级和流级的多级特征构造方法,通过将网络流按照时间窗口划分为多个流段,既保留了流的时序特性,又实现了对特征的细粒度刻画。这种方法能够更全面地描述网络流量的特性。
-
深度学习与传统机器学习结合:创新性地将自动编码器和聚类算法相结合,用于段级特征的编码和融合。自动编码器用于学习行为特征的低维表示,聚类算法用于将编码后的特征与统计特征进行融合,这种结合充分发挥了两种方法的优势。
-
自适应特征融合策略:通过K-Means聚类算法将段级特征转换为聚类中心的分布特征,实现了特征的自适应融合。这种方法能够根据数据的内在结构自动发现和提取重要特征,避免了手动特征选择的局限性。
基于记忆模块的流量异常检测方法
-
多角度特征扩展方法:提出了一套针对元数据场景的多角度特征扩展方法,包括滑动窗口统计特征、地理位置突变特征、攻击规则特征和基线规则特征。这些特征从不同角度丰富了元数据的表示,提高了特征的信息量。
-
双存储器记忆模块设计:创新性地设计了由两个存储器组成的记忆模块,M1存储最近的正常样本,M2存储历史正常样本。这种设计既考虑了数据的时效性,又兼顾了历史经验,能够更全面地捕获正常行为模式。
-
自适应模型更新机制:提出了基于异常比例的自适应模型更新机制,当检测到数据分布发生显著变化时,自动触发模型更新,重新训练自动编码器。这种机制能够有效应对数据漂移问题,保持模型的长期有效性。
-
综合异常评分方法:结合自动编码器的重构误差和记忆模块的距离度量,提出了一种综合异常评分方法。这种方法不仅考虑了样本与正常模式的差异,还考虑了样本与历史记忆的相似度,提高了异常检测的准确性。
面向智能电网的流量入侵检测系统
-
多方法融合的检测策略:系统结合了规则检测和异常检测两种方法,通过Suricata引擎进行规则匹配,通过自定义算法进行异常检测,充分发挥了两种方法的优势,提高了检测的准确性和全面性。
-
分布式部署架构:采用分布式部署架构,将系统分为agent、server和state三个节点,各节点之间分工协作,既保证了系统的可扩展性,又提高了系统的可靠性和容错性。
-
实时数据分析和可视化:基于ELK框架构建了实时的数据分析和可视化系统,能够对网络流量和检测结果进行实时分析和展示,为安全管理人员提供直观、全面的安全态势感知。
总结
本研究针对当前网络入侵检测技术面临的挑战,提出了基于多级特征融合的流量分类方法和基于记忆模块的流量异常检测方法,并构建了面向智能电网的流量入侵检测系统。通过理论研究、算法设计和系统实现,取得了以下主要成果:
-
多级特征融合的流量分类方法,通过提取段级和流级的多级特征,并结合自动编码器和聚类算法进行特征融合,有效解决了传统方法特征挖掘不充分的问题。实验结果表明,该方法在智能电网真实流量数据上的F1分数达到0.9834,优于对比模型,能够准确识别不同类型的终端设备。
-
基于记忆模块的流量异常检测方法,通过多角度的特征扩展和双存储器的记忆模块设计,有效解决了元数据场景下的特征不足和数据漂移问题。实验结果表明,该方法在三个公开数据集上的AUROC指标均位列第一,能够准确检测各类网络异常行为。
-
构建了面向智能电网的流量入侵检测系统,将提出的算法整合到实际系统中,结合Suricata引擎和ELK框架,实现了流量采集、检测和可视化的全流程。系统采用分布式部署架构,具有良好的可扩展性和可靠性,能够满足智能电网环境下的安全监控需求。
本研究也存在一些局限性和未来的研究方向。例如,在特征提取和融合方面,还可以探索更高效的特征表示学习方法;在模型设计方面,还可以优化损失函数,提高模型的鲁棒性;在系统实现方面,还可以进一步优化性能,提高实时处理能力。未来的研究可以围绕这些方向展开,进一步提升网络入侵检测技术的性能和实用性。
参考文献
-
[1] LEE D, KIM H, YOON J. Network traffic classification using deep learning: A survey[J]. IEEE Communications Surveys & Tutorials, 2023, 25(2): 1254-1274.
-
[2] WANG X, ZHANG Y, LIU J, et al. A novel intrusion detection system based on feature fusion and ensemble learning[J]. Computers & Security, 2022, 118: 102710.
-
[3] ZHOU Y, ZHANG Y, LIU Y, et al. Memory-augmented deep autoencoder for anomaly detection in multivariate time series[J]. IEEE Transactions on Neural Networks and Learning Systems, 2023, 34(5): 2412-2425.
-
[4] ZHANG X, WANG L, WU J, et al. A survey on network anomaly detection methods[J]. IEEE Communications Surveys & Tutorials, 2020, 22(1): 453-475.
-
[5] MA Y, ZHANG Z, YU S, et al. Multi-level feature fusion for network traffic classification[J]. Journal of Network and Computer Applications, 2021, 182: 103080.
-
[6] LIU Z, LI Y, XU N, et al. Adaptive anomaly detection based on memory network for IoT security[J]. IEEE Internet of Things Journal, 2023, 10(12): 10726-10739.
-
[7] ZHANG H, DING S, ZHANG L, et al. An adaptive intrusion detection system for smart grid communications[J]. IEEE Transactions on Smart Grid, 2022, 13(5): 3858-3869.
-
[8] CHEN K, LIU Y, ZHANG J, et al. Deep learning-based network intrusion detection: A survey of recent works and challenges[J]. IEEE Access, 2021, 9: 77797-77819.
1084



被折叠的 条评论
为什么被折叠?



