十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于深度学习的恶意加密流量检测系统:从pcap到实时推理的完整实现

基于深度学习的恶意加密流量检测系统:从pcap到实时推理的完整实现 简介这份资源是面向高校计算机、网络安全相关专业学生的毕业设计与课程设计参考包主题为基于深度学习的恶意加密流量检测系统的设计与实现。项目围绕加密流量的特征提取与分类识别展开涉及DoH、CTU-13等数据集的预处理、特征筛选与模型训练评估适合具备Python基础、希望完成安全方向高分毕设或期末大作业的学习者。压缩包共217个文件约25.61MB包含4个Python源码文件、6个CSV特征与结果数据、6个NPY数据文件、2个PCAP流量样本以及14个HTML可视化页面、8张JPG与7张PNG图表、165个日志文件另附说明文档与样式资源代码注释完整新手也能理解。目前已有251人学习下载。整体方案覆盖数据清洗、特征工程、模型对比到结果展示的完整链路可直接部署运行帮助读者快速搭建实验环境、理解检测流程并完成论文与答辩准备。1. 从一条加密流里判断“它是不是恶意”难点到底在哪很多人第一次做恶意加密流量检测会下意识觉得加密了那就先解密再分析。这条路在真实场景里基本走不通——TLS 1.3 普及之后证书、密钥、会话票据层层加码中间人解密既不可扩展也涉及隐私和合规问题。所以这个毕业设计真正要解决的问题是在不解密的前提下仅凭流量外部特征判断这条加密会话是否恶意。这正是深度学习能插进来的地方。传统机器学习模型依赖人工设计的统计特征比如包长分布、到达间隔、上下行字节比特征工程做得好能到 90% 出头但换一个网络环境、换一批恶意家族指标就掉得厉害。深度学习尤其是 CNN、LSTM 这类结构能直接从原始字节序列或包序列里学表征泛化能力更强这也是“基于深度学习的恶意加密流量检测系统”这个选题在毕业设计里一直热门的原因。这套系统适合谁适合计算机、网络安全方向的本科或研究生需要一份能跑通、能讲清原理、有源码和文档说明的完整工程。下面按“数据怎么来 → 模型怎么搭 → 系统怎么落地 → 怎么调优排错”的顺序把我会怎么做讲清楚。2. 恶意加密流量数据集与特征工程从 pcap 到模型输入2.1 公开数据集怎么选为什么不能只用一种做这个方向第一步不是写模型是找数据。常见做法是组合使用几个公开数据集避免单一来源导致模型过拟合到某个采集环境。数据集流量类型标注粒度适用场景CIC-IDS2017混合含加密流级入门基线样本量大USTC-TFC2016恶意软件流量流级恶意家族分类ISCX-VPN2016加密应用流量流级加密流量识别CIC-Darknet2020暗网加密流量流级二分类/多分类我一般会先用 USTC-TFC2016 做恶意/正常的二分类基线再叠加 CIC-IDS2017 扩充正常流量最后用 ISCX-VPN2016 做跨数据集验证。注意不同数据集的 pcap 时间戳、链路层类型可能不一致合并前必须统一。2.2 用 Python 把 pcap 切成会话流原始 pcap 不能直接喂给模型要先按五元组切分成流。常见做法是用scapy或dpkt解析按 (源IP, 源端口, 目的IP, 目的端口, 协议) 聚合。from scapy.all import rdpcap, IP, TCP, UDP from collections import defaultdict def split_flows(pcap_path, max_packets20): 把 pcap 按五元组切成流每条流最多保留 max_packets 个包 packets rdpcap(pcap_path) flows defaultdict(list) for pkt in packets: if IP not in pkt: continue proto TCP if TCP in pkt else (UDP if UDP in pkt else OTHER) if proto OTHER: continue # 双向流统一用排序后的五元组做 key避免上下行被拆成两条 key tuple(sorted([ (pkt[IP].src, pkt[TCP].sport if TCP in pkt else pkt[UDP].sport), (pkt[IP].dst, pkt[TCP].dport if TCP in pkt else pkt[UDP].dport) ])) (proto,) if len(flows[key]) max_packets: flows[key].append(pkt) return flows逻辑说明split_flows先把 pcap 读进内存逐包判断协议类型用排序后的五元组作为 key保证同一条会话的上下行包归到同一个流里。max_packets20是截断长度因为大部分恶意流量的判别信息集中在前 10 到 20 个包截断既能统一输入维度又能减少计算量。参数说明max_packets建议在 10 到 50 之间调太小会丢信息太大则 padding 过多、噪声增加。如果内存吃紧可以用PcapReader流式读取替代rdpcap。2.3 特征表示字节序列还是统计特征切完流之后有两条路。一条是把每个包的前 N 个字节取出来拼成字节序列直接送进一维 CNN另一条是提取统计特征包长均值、方差、到达间隔、TLS 握手字段等送进全连接网络或树模型。我的建议是两条路都做最后融合。字节序列保留原始信息统计特征提供可解释性。具体做法import numpy as np def packet_to_bytes(pkt, max_len64): 取包的前 max_len 字节不足补 0 raw bytes(pkt)[:max_len] return np.pad(np.frombuffer(raw, dtypenp.uint8), (0, max_len - len(raw)), constant) def extract_stats(flow): 提取一条流的统计特征 lengths [len(p) for p in flow] times [float(p.time) for p in flow] iats np.diff(times) if len(times) 1 else [0] return np.array([ np.mean(lengths), np.std(lengths), np.mean(iats), np.std(iats), len(flow) ], dtypenp.float32)逻辑说明packet_to_bytes把每个包截断或补齐到固定长度保证 CNN 输入维度一致extract_stats提取包长和到达间隔的均值、方差这些是加密流量分类里最稳定的特征。参数说明max_len64覆盖了 TLS 握手和大部分应用层头部再长收益递减。统计特征维度控制在 5 到 15 维太多会引入噪声太少区分度不够。注意切流时一定要做双向合并否则同一条 TLS 会话的 ClientHello 和 ServerHello 会被拆成两条流模型学到的模式是残缺的。3. 深度学习模型设计CNN、LSTM 与混合结构的取舍3.1 为什么一维 CNN 是加密流量检测的基线首选加密流量的字节序列里判别信息往往藏在局部模式中比如 TLS 握手里特定字段的取值、包长序列的周期性。一维 CNN 的卷积核正好能捕捉这种局部模式而且参数量小、训练快适合毕业设计的算力条件。import torch import torch.nn as nn class ByteCNN(nn.Module): def __init__(self, num_classes2, max_len64): super().__init__() self.conv nn.Sequential( nn.Conv1d(1, 32, kernel_size3, padding1), nn.BatchNorm1d(32), nn.ReLU(), nn.MaxPool1d(2), nn.Conv1d(32, 64, kernel_size3, padding1), nn.BatchNorm1d(64), nn.ReLU(), nn.AdaptiveAvgPool1d(1) ) self.fc nn.Linear(64, num_classes) def forward(self, x): # x: (batch, 1, max_len) x self.conv(x) x x.squeeze(-1) return self.fc(x)逻辑说明两层一维卷积第一层 32 个卷积核提取低阶字节模式第二层 64 个卷积核组合成高阶模式。BatchNorm1d加速收敛AdaptiveAvgPool1d(1)把变长序列压成固定维度最后全连接分类。参数说明kernel_size3是常用起点想捕捉更长模式可以加到 5 或 7但要注意 padding 同步调整。num_classes2是二分类做恶意家族多分类时改成实际类别数。3.2 LSTM 补上时序信息混合模型怎么拼CNN 擅长局部模式但对包与包之间的时序依赖不敏感。加密流量的到达间隔、包长变化本身就是一个时间序列LSTM 能建模这种依赖。常见做法是 CNN 提特征、LSTM 建时序最后拼接统计特征做分类。class CNNLSTM(nn.Module): def __init__(self, num_classes2, max_len64, stat_dim5): super().__init__() self.cnn nn.Sequential( nn.Conv1d(1, 32, 3, padding1), nn.ReLU(), nn.MaxPool1d(2), nn.Conv1d(32, 64, 3, padding1), nn.ReLU() ) self.lstm nn.LSTM(64, 64, batch_firstTrue, bidirectionalTrue) self.stat_fc nn.Linear(stat_dim, 16) self.classifier nn.Sequential( nn.Linear(128 16, 64), nn.ReLU(), nn.Dropout(0.3), nn.Linear(64, num_classes) ) def forward(self, x_byte, x_stat): # x_byte: (batch, 1, max_len), x_stat: (batch, stat_dim) x self.cnn(x_byte) # (batch, 64, max_len/2) x x.permute(0, 2, 1) # (batch, seq, 64) _, (h, _) self.lstm(x) # h: (2, batch, 64) h torch.cat([h[0], h[1]], dim1) # 双向拼接 s torch.relu(self.stat_fc(x_stat)) return self.classifier(torch.cat([h, s], dim1))逻辑说明CNN 输出经过permute变成 LSTM 需要的 (batch, seq, feature) 格式双向 LSTM 取最后一个时间步的隐藏状态正反两个方向拼接成 128 维再和统计特征的 16 维拼接送进分类头。参数说明Dropout(0.3)防止过拟合数据量小的时候可以加到 0.5。bidirectionalTrue让模型同时看前后文代价是参数量翻倍算力紧张时可以关掉。3.3 训练时的类别不平衡与早停策略恶意流量数据集里正常流量通常远多于恶意流量直接训练模型会偏向多数类。常见做法是在损失函数里加权重或者用重采样。from torch.utils.data import DataLoader, WeightedRandomSampler # 假设 labels 是全部训练样本的标签列表 class_counts np.bincount(labels) weights 1.0 / class_counts[labels] sampler WeightedRandomSampler(weights, num_sampleslen(weights), replacementTrue) loader DataLoader(dataset, batch_size64, samplersampler) criterion nn.CrossEntropyLoss(weighttorch.tensor([1.0, 3.0]))逻辑说明WeightedRandomSampler让少数类样本被采到的概率更高CrossEntropyLoss的weight参数进一步放大少数类损失。两者叠加能明显改善召回率。参数说明weight[1.0, 3.0]里的 3.0 是经验值实际按正负样本比例调比例 1:10 时可以设到 5.0 以上。早停建议监控验证集 F1连续 5 个 epoch 不提升就停。注意不要只看准确率。类别不平衡时准确率会虚高恶意流量的召回率和 F1 才是关键指标。4. 系统落地从模型到可交互的检测系统4.1 系统架构与模块划分毕业设计不只是训一个模型还要有一套能演示的系统。常见架构分四层数据采集层pcap 读取或网卡抓包、预处理层切流、特征提取、检测层加载模型推理、展示层Web 界面或命令行。用 Python 落地时我一般用 Flask 做后端接口前端用简单的 HTML 加 ECharts 展示检测结果。核心接口就两个上传 pcap 返回检测报告以及实时抓包检测。from flask import Flask, request, jsonify import torch app Flask(__name__) model CNNLSTM(num_classes2) model.load_state_dict(torch.load(best_model.pth, map_locationcpu)) model.eval() app.route(/detect, methods[POST]) def detect(): file request.files[pcap] file.save(/tmp/upload.pcap) flows split_flows(/tmp/upload.pcap) results [] for key, pkts in flows.items(): byte_seq np.stack([packet_to_bytes(p) for p in pkts]) stat extract_stats(pkts) with torch.no_grad(): x_byte torch.tensor(byte_seq, dtypetorch.float32).unsqueeze(0).unsqueeze(0) x_stat torch.tensor(stat, dtypetorch.float32).unsqueeze(0) logits model(x_byte, x_stat) pred torch.argmax(logits, dim1).item() results.append({flow: str(key), label: malicious if pred else benign}) return jsonify(results)逻辑说明接口接收 pcap 文件复用前面的切流和特征提取函数逐条流推理返回每条流的判定结果。model.eval()和torch.no_grad()关闭训练相关行为减少内存占用。参数说明map_locationcpu保证没有 GPU 也能加载模型答辩演示时更稳妥。批量推理可以把多条流拼成一个 batch速度更快。4.2 模型导出与推理加速PyTorch 模型直接部署在 CPU 上推理速度一般毕业设计里可以用 ONNX 导出再用 ONNX Runtime 推理速度能提升 2 到 3 倍。import torch.onnx dummy_byte torch.randn(1, 1, 64) dummy_stat torch.randn(1, 5) torch.onnx.export( model, (dummy_byte, dummy_stat), model.onnx, input_names[byte_seq, stat_feat], output_names[logits], dynamic_axes{byte_seq: {0: batch}, stat_feat: {0: batch}} )逻辑说明dynamic_axes把 batch 维度设为动态这样导出后的模型能处理任意 batch size。导出后用onnxruntime.InferenceSession加载即可。参数说明如果模型里有 LSTM导出时注意 opset 版本建议用 12 以上。导出后务必用同一批数据对比 PyTorch 和 ONNX 的输出确认数值一致。4.3 检测结果的可视化与报告生成答辩时老师最想看的是“系统跑起来什么样”。我一般会做一个页面展示每条流的五元组、判定结果、置信度再用饼图统计恶意/正常比例。报告用jinja2模板生成 HTML或者用reportlab导出 PDF。from jinja2 import Template REPORT_TMPL Template( h2检测报告/h2 p总流数{{ total }}/p p恶意流数{{ malicious }}/p table border1 trth流/thth判定/thth置信度/th/tr {% for r in results %} trtd{{ r.flow }}/tdtd{{ r.label }}/tdtd{{ r.conf }}/td/tr {% endfor %} /table )逻辑说明模板渲染把推理结果转成 HTML 表格置信度用 softmax 后的概率值。前端再加一个 ECharts 饼图视觉效果就够了。参数说明置信度阈值可以设成 0.5也可以按业务需求调高到 0.8 减少误报。报告里建议保留原始五元组方便溯源。5. 调优与排错指标上不去时先查这几处5.1 验证指标虚高数据泄漏的三种典型表现模型在验证集上 F1 到 0.99换一批数据就崩八成是数据泄漏。常见三种一是切流时同一条会话的包被分到训练集和验证集二是同一 pcap 文件被随机切分三是特征里混入了标签相关字段。排查方法按 pcap 文件或时间戳做划分而不是按流随机划分。用GroupShuffleSplit按文件分组确保同一来源的流只出现在一个集合里。from sklearn.model_selection import GroupShuffleSplit gss GroupShuffleSplit(n_splits1, test_size0.2, random_state42) train_idx, val_idx next(gss.split(X, y, groupsfile_ids))逻辑说明groupsfile_ids保证同一个 pcap 文件的所有流要么全在训练集要么全在验证集杜绝泄漏。参数说明test_size0.2是常用比例数据量小时可以调到 0.3。random_state固定后结果可复现写论文时很重要。5.2 跨数据集泛化差域偏移怎么缓解在 USTC-TFC2016 上训的模型拿到 ISCX-VPN2016 上测F1 掉 20 个点很正常这是域偏移。缓解手段有三类一是加数据增强比如对包长序列做随机扰动二是用域适应方法比如在损失里加 MMD 或对抗训练三是简单粗暴地混合多个数据集一起训。我一般先试混合训练成本最低。如果还不行再上域适应。毕业设计里能把混合训练和跨数据集验证讲清楚已经够用了。5.3 推理延迟高从模型剪枝到批处理系统演示时如果每条流推理要几百毫秒体验很差。优化顺序先看是不是逐条推理改成批处理再看模型是不是太大可以剪枝或换轻量结构最后考虑 ONNX Runtime 或 TensorRT。# 批处理推理示例 batch_bytes torch.stack([...]) # (N, 1, 64) batch_stats torch.stack([...]) # (N, 5) with torch.no_grad(): logits model(batch_bytes, batch_stats) preds torch.argmax(logits, dim1)逻辑说明把 N 条流拼成一个 batch一次前向传播出结果比循环快一个数量级。参数说明batch size 按内存调CPU 推理建议 32 到 128。太大反而会因为内存交换变慢。5.4 常见报错与对应处理报错原因处理CUDA out of memorybatch 太大或模型太大减小 batch或改用 CPUExpected 3D inputCNN 输入维度不对检查 unsqueeze 是否加了通道维NaN loss学习率过高或数据有 NaN降学习率检查特征归一化pcap 读取为空链路层类型不支持用rdpcap前先确认链路类型注意特征归一化一定要在训练集上算均值和方差再应用到验证集和测试集否则又是一次数据泄漏。6. 把模型压到能实时跑的技巧量化与滑动窗口检测前面讲的都是离线检测实际场景里更希望系统能对实时流量做在线判断。这里给一个具体技巧用滑动窗口把连续流量切成片段配合动态量化把模型压小做到接近实时的推理速度。先做动态量化PyTorch 一行就能把 LSTM 和全连接层的权重从 float32 压到 int8import torch.quantization quantized_model torch.quantization.quantize_dynamic( model, {nn.LSTM, nn.Linear}, dtypetorch.qint8 ) torch.save(quantized_model.state_dict(), quantized.pth)逻辑说明quantize_dynamic只量化 LSTM 和 Linear 层卷积层保持 float32因为卷积量化收益小、精度损失大。量化后模型体积通常缩小到原来的四分之一CPU 推理速度提升明显。参数说明dtypetorch.qint8是动态量化的标准选择。量化后务必在验证集上重新测 F1掉点超过 2 个点就要考虑只量化部分层。再做滑动窗口。实时抓包时不能等一条流结束再判断而是每来一批包就推理一次from collections import deque window deque(maxlen20) # 滑动窗口保留最近 20 个包 def on_packet(pkt): window.append(pkt) if len(window) 20: byte_seq np.stack([packet_to_bytes(p) for p in window]) stat extract_stats(list(window)) # 推理逻辑同上输出当前窗口的判定逻辑说明deque(maxlen20)自动丢弃最旧的包保持窗口大小固定。每满 20 个包推理一次输出当前窗口的恶意概率实现准实时检测。参数说明窗口大小和训练时的max_packets保持一致否则分布不匹配。推理间隔可以按包数也可以按时间按时间更贴近真实场景。最后给一个验证量化效果的小脚本对比原始模型和量化模型在同一批数据上的输出差异def compare_models(orig, quant, loader): orig.eval(); quant.eval() diff 0; total 0 for xb, xs, _ in loader: with torch.no_grad(): o torch.argmax(orig(xb, xs), dim1) q torch.argmax(quant(xb, xs), dim1) diff (o ! q).sum().item() total o.size(0) print(f预测不一致比例: {diff / total:.4f})逻辑说明逐 batch 对比两个模型的预测类别统计不一致比例。这个比例控制在 1% 以内量化就算合格。参数说明loader用验证集即可不用测试集避免反复调参导致过拟合。如果差异过大回退到只量化 Linear 层。本文还有配套的精品资源点击获取
返回列表