Iditc/CIC-IDS2017-analysis

GitHub: Iditc/CIC-IDS2017-analysis

该项目利用机器学习技术对 CIC-IDS2017 数据集进行端到端的网络入侵检测分析,涵盖数据预处理、特征工程、模型训练与多类别攻击分类评估。

Stars: 0 | Forks: 0

# CIC-IDS2017-analysis 本项目将机器学习技术应用于使用 CIC-IDS2017 数据集的网络入侵检测。涵盖了数据预处理、特征工程、模型训练与评估——将网络流量分类为良性或恶意,涵盖多种攻击类别,包括 DDoS、PortScan 和 Brute Force。 ## 文件 ### `preprocessing/` | 文件 | 描述 | |------|-------------| | `download_data.py` | 下载并保存数据集到 `data/raw/` | | `load_data.py` | 加载所有 CSV 文件,规范化列名,删除 NaN/Inf 行,应用特征选择 | | `basic_feature_selection.py` | 三轮特征选择:零方差 → 特征间相关性 → 标签相关性 | | `data_cleaning.py` | 删除重复行和 NaN/Inf 行;将清理后的数据集保存到 `data/processed/clean.parquet` | ### `eda/` | 文件 | 描述 | |------|-------------| | `dataset_overview.py` | 数据形状、缺失值、类别分布、标签描述 | | `eda.py` | 标签分布图、相关性热力图、最具区分度的特征 | | `feature_descriptions.py` | 包含全部 79 个特征的类别和描述的完整表格 | | `describe_features.py` | 每个特征的均值、标准差、最小值、最大值、偏度和异常值百分比 | ### `models/` | 文件 | 描述 | |------|-------------| | `baseline_random_forest.py` | 无类别平衡的 Random Forest — 作为基准参考 | | `balanced_random_forest.py` | 带有 `class_weight='balanced'` 的 Random Forest | | `utils.py` | 共享工具:标签重映射、混淆矩阵绘制、对比 CSV | ## 运行 ``` python main.py ``` ## 特征 | 特征 | 描述 | |---|---| | Destination Port | 目标端口号(例如:80=HTTP, 443=HTTPS, 22=SSH) | | Flow Duration | 流的总持续时间(微秒) | | Total Fwd Packets | 向前(客户端 → 服务器)发送的数据包总数 | | Total Backward Packets | 向后(服务器 → 客户端)发送的数据包总数 | | Total Length of Fwd Packets | 向前数据包的载荷总字节数 | | Total Length of Bwd Packets | 向后数据包的载荷总字节数 | | Fwd Packet Length Max | 最大的向前数据包大小(字节) | | Fwd Packet Length Min | 最小的向前数据包大小(字节) | | Fwd Packet Length Mean | 平均向前数据包大小(字节) | | Fwd Packet Length Std | 向前数据包大小的标准差 | | Bwd Packet Length Max | 最大的向后数据包大小(字节) | | Bwd Packet Length Min | 最小的向后数据包大小(字节) | | Bwd Packet Length Mean | 平均向后数据包大小(字节) | | Bwd Packet Length Std | 向后数据包大小的标准差 | | Flow Bytes/s | 整个流中每秒的总字节数 | | Flow Packets/s | 整个流中每秒的总数据包数 | | Flow IAT Mean | 流中任意两个连续数据包之间的平均时间(µs) | | Flow IAT Std | 到达时间的标准差 | | Flow IAT Max | 两个连续数据包之间最长的间隔时间(µs) | | Flow IAT Min | 两个连续数据包之间最短的间隔时间(µs) | | Fwd IAT Total | 向前数据包之间的总时间(µs) | | Fwd IAT Mean | 向前数据包的平均到达间隔时间(µs) | | Fwd IAT Std | 向前 IAT 的标准差 | | Fwd IAT Max | 向前数据包之间最长的间隔时间(µs) | | Fwd IAT Min | 向前数据包之间最短的间隔时间(µs) | | Bwd IAT Total | 向后数据包之间的总时间(µs) | | Bwd IAT Mean | 向后数据包的平均到达间隔时间(µs) | | Bwd IAT Std | 向后 IAT 的标准差 | | Bwd IAT Max | 向后数据包之间最长的间隔时间(µs) | | Bwd IAT Min | 向后数据包之间最短的间隔时间(µs) | | Fwd PSH Flags | 带有 PSH 标志(立即将数据推送到应用层)的向前数据包数量 | | Bwd PSH Flags | 带有 PSH 标志的向后数据包数量 | | Fwd URG Flags | 带有 URG 标志(紧急数据)的向前数据包数量 | | Bwd URG Flags | 带有 URG 标志的向后数据包数量 | | Fwd Header Length | 向前数据包中头部使用的总字节数 | | Bwd Header Length | 向后数据包中头部使用的总字节数 | | Fwd Packets/s | 每秒向前数据包数 | | Bwd Packets/s | 每秒向后数据包数 | | Min Packet Length | 整个流中最小的数据包(字节) | | Max Packet Length | 整个流中最大的数据包(字节) | | Packet Length Mean | 整个流中的平均数据包大小(字节) | | Packet Length Std | 数据包大小的标准差 | | Packet Length Variance | 数据包大小的方差(Std²) | | FIN Flag Count | 带有 FIN 标志(连接拆除)的数据包数量 | | SYN Flag Count | 带有 SYN 标志的数据包数量 — 数值过高可能表明存在 SYN flood | | RST Flag Count | 带有 RST 标志(突然重置连接)的数据包数量 | | PSH Flag Count | 所有数据包中 PSH 标志的总数 | | ACK Flag Count | 带有 ACK 标志(确认)的数据包数量 | | URG Flag Count | 所有数据包中 URG 标志的总数 | | CWE Flag Count | 带有 CWE 标志(拥塞窗口减少回显)的数据包数量 | | ECE Flag Count | 带有 ECE 标志(显式拥塞通知回显)的数据包数量 | | Down/Up Ratio | 下载(向后)流量与上传(向前)流量的比率 | | Average Packet Size | 双向的平均数据包大小(字节) | | Avg Fwd Segment Size | 平均向前 TCP segment size | | Avg Bwd Segment Size | 平均向后 TCP segment size | | Fwd Avg Bytes/Bulk | 向前方向每次批量传输的平均字节数 | | Fwd Avg Packets/Bulk | 向前方向每次批量传输的平均数据包数 | | Fwd Avg Bulk Rate | 向前方向的平均批量传输速率(bytes/s) | | Bwd Avg Bytes/Bulk | 向后方向每次批量传输的平均字节数 | | Bwd Avg Packets/Bulk | 向后方向每次批量传输的平均数据包数 | | Bwd Avg Bulk Rate | 向后方向的平均批量传输速率(bytes/s) | | Subflow Fwd Packets | 每个 subflow 中向前数据包的平均数量 | | Subflow Fwd Bytes | 每个 subflow 中向前数据包的平均字节数 | | Subflow Bwd Packets | 每个 subflow 中向后数据包的平均数量 | | Subflow Bwd Bytes | 每个 subflow 中向后数据包的平均字节数 | | Init_Win_bytes_forward | 向前方向的初始 TCP 窗口大小(字节) | | Init_Win_bytes_backward | 向后方向的初始 TCP 窗口大小(字节) | | act_data_pkt_fwd | 携带实际 payload 的向前数据包数量 | | min_seg_size_forward | 向前方向的最小 TCP segment size | | Active Mean | 流在进入空闲状态前的平均活跃时间(µs) | | Active Std | 活跃周期的标准差 | | Active Max | 最长的活跃周期(µs) | | Active Min | 最短的活跃周期(µs) | | Idle Mean | 活跃周期之间流的平均空闲时间(µs) | | Idle Std | 空闲周期的标准差 | | Idle Max | 最长的空闲周期(µs) | | Idle Min | 最短的空闲周期(µs) | | Label | 流量分类:BENIGN 或攻击类型(DDoS, PortScan, Brute Force 等) | ## 缺失值 两个特征包含缺失值(各占行数的 0.1%): - **Flow Bytes/s** — 流中每秒的总字节数。有 2,867 行缺失(0.1%)。与标签的相关性:待定(待分析)。 - **Flow Packets/s** — 流中每秒的总数据包数。有 2,867 行缺失(0.1%)。与标签的相关性:待定(待分析)。 这两个特征影响的行相同(缺失值位于相同位置)。鉴于缺失率极低(0.1%),这些行将在预处理阶段被删除。相关性分析将确定这些特征是否包含有意义的信号。 ## 数据清洗 原始数据集包含 2,830,743 行。在训练前应用了两个清洗步骤: ### 步骤 1 — 去重 完全重复的行(所有特征值完全相同)被识别并删除,仅保留每个组的第一次出现。 - 删除的行数:**309,956**(占数据集的 10.95%) - 大多数重复项来自 BENIGN 流量和常见攻击类型(DoS Hulk、PortScan) - 去重后:**2,520,787 行** ### 步骤 2 — 删除 NaN 和无穷大值 两个特征 — `Flow Bytes/s` 和 `Flow Packets/s` — 包含由 CICFlowMeter 在 flow duration 为零(除以零)时产生的无穷大值。任何至少包含一个 NaN 或 Inf 值的行均被删除。 - 删除的行数:**~2,867**(占数据集的 0.1%) - 仅这两个特征受到影响;所有其他特征均完整 ### 结果 清洗后的数据集包含 **2,520,787 行**,并保存至 `data/processed/clean.parquet`。 ## 基准模型 Random Forest 分类器(100 棵树)在清洗后的数据集上进行了训练,作为应用任何类别平衡或特征工程之前的参考基准。 ### 设置 - **训练 / 测试集划分:** 80% / 20%,按类别分层 - **Web Attack 合并:** 三个 Web Attack 子类(Brute Force、XSS、SQL Injection)被合并为一个单独的 `Web Attack` 标签。每个子类的样本过少(测试集中只有 4–294 个),无法进行可靠的单独评估,并且模型经常将它们互相混淆。合并将类别数量从 15 个减少到 13 个。 ### 结果 | 模型 | F1 Macro | Recall Bot | Recall Web Attack | Recall Infiltration | |-------|----------|-----------|-------------------|---------------------| | 基准(无平衡) | 0.9511 | 0.771 | 0.972 | 0.857 | | 平衡(`class_weight='balanced'`) | 0.9572 | 0.774 | 0.974 | 1.000 | ### 关键发现 - 两个模型总体表现良好(F1 Macro > 0.95) - **Bot** 是最难检测的类别 — 两个模型都漏掉了约 25% 的 Bot 流量。Bot 流量故意模拟正常的 HTTP 通信,使得仅使用网络流特征很难区分 - `class_weight='balanced'` 对基准模型的改善微乎其微。对于非常罕见的类别(Heartbleed:总共 11 个样本,Infiltration:36 个),即使加重权重也无法弥补训练数据的不足 - **Heartbleed 和 Infiltration** 的结果在统计学上不可靠,因为测试集规模极小(分别只有 2 个和 7 个样本) - 结果保存至 `output/models/`,包含每个模型的混淆矩阵和核心对比表 ## 特征工程 从清洗后的数据集中创建了 19 个新特征,并保存至 `data/processed/engineered.parquet`。原始的 `clean.parquet` 未被修改。 | 组别 | 特征 | 原理 | |-------|----------|-----------| | **端口类别** (9) | `port_is_well_known`, `port_is_http`, `port_is_https`, `port_is_ssh`, `port_is_dns`, `port_is_ftp`, `port_is_rdp`, `port_is_registered`, `port_is_dynamic` | 原始端口号有 53,805 个唯一值 — 二进制标志更具可解释性 | | **比率** (2) | `fwd_bytes_per_packet`, `header_to_payload_ratio` | 比率比原始计数包含更多信息(例如:每个包的字节数 vs 总字节数) | | **数据包大小变异性** (2) | `fwd_packet_size_range`, `bwd_packet_size_range` | 自动化攻击发送大小均匀的数据包而合法流量则有所变化 | | **TCP 标志比率** (3) | `rst_ratio`, `fin_ratio`, `psh_ratio` | 高 RST = 端口扫描;高 PSH = 数据突发;高 FIN = 拆除连接攻击 | | **持续时间分箱** (3) | `is_very_short_flow`, `is_very_long_flow`, `duration_per_fwd_packet` | 端口扫描产生极短的流;Bot 产生极长的流 | ## 模型结果 所有模型均使用 80/20 分层训练/测试集划分。三个 Web Attack 子类(Brute Force、XSS、SQL Injection)被合并为一个单独的 `Web Attack` 标签 — 每个子类的样本太少,无法进行可靠的单独评估。 ### 对比表 | 模型 | 测试集 F1 Macro | 训练集 F1 | 差距 | Recall Bot | Recall Web Attack | |-------|--------------|----------|-----|-----------|------------------| | 基准 — 清洗数据 | 0.9511 | — | — | 0.771 | 0.972 | | 平衡 — 清洗数据 | 0.9572 | — | — | 0.774 | 0.974 | | 基准 — 特征工程 | 0.9564 | 0.9998 | 0.0433 | 0.763 | 0.977 | | 平衡 — 特征工程 | 0.9571 | 0.9998 | 0.0427 | 0.769 | 0.977 | | **调优后 (200 棵树, depth=30)** | **0.9568** | 0.9997 | **0.0429** | 0.771 | 0.977 | ### 关键发现 - **特征工程发挥了作用** — 在最重要的 10 个特征中,有 5 个是工程化的。`psh_ratio`(带有 PSH 标志的数据包比例)在所有模型中始终是最重要的特征 - **`class_weight='balanced'` 提供的改善微乎其微** — 罕见类别实在太少,仅靠加权无法弥补 - **Bot 仍然是最难的类别** — 在所有模型中 Recall 约为 0.77。Bot 流量故意模拟正常的 HTTP 通信,使得仅靠网络流特征很难区分 - **过拟合差距适中**(~0.04)— 对于 Random Forest 来说可以接受,但也表明模型记忆了某些训练模式。限制 `max_depth=30` 在不损害测试性能的情况下缩小了差距 - **Random Forest 已达到上限** — 所有特征工程模型变体之间的 F1 Macro 差异均不到 0.001。要想进一步提升,需要使用其他算法(XGBoost、LightGBM 或深度学习) ### 基准测试背景 与 CIC-IDS2017 上已发表的结果相比: - 文献中的 Random Forest 通常达到 F1 Macro ~0.93 - 我们的最佳结果 (0.957) **超越了典型的 Random Forest 基准** - 最先进的模型(Stacking、深度学习)达到 F1 Macro ~0.98 ## Bot 检测 — 专注的二分类器 在多分类模型中,Bot 是最难分类的类别(Recall ~0.77)。我们训练了一个专门的二分类器来回答一个问题:**“这个流是 Bot 吗?”** ### 设置 - **模型:** Random Forest(200 棵树,max_depth=30,class_weight='balanced') - **标签:** Bot=1,其他所有=0 - **数据集:** engineered.parquet(2,520,787 行,61 个特征) - **Bot 样本:** 1,948(占数据集的 0.077%) ### 阈值分析 | 阈值 | Recall | Precision | F1 | |-----------|--------|-----------|-----| | 0.1 | 0.990 | 0.574 | 0.727 | | 0.2 | 0.982 | 0.680 | 0.804 | | **0.3** | **0.967** | **0.702** | **0.813** | | 0.4 | 0.941 | 0.708 | 0.808 | | 0.5 | 0.913 | 0.719 | 0.805 | **选定阈值:0.3** — 在 Recall=0.967 的情况下取得最佳 F1 (0.813)。在安全领域,漏掉一个 Bot 比误报更严重,因此更倾向于较高的 Recall。 ### 与多分类模型对比 | 模型 | Bot Recall | |-------|-----------| | 多分类 Random Forest | 0.774 | | **Bot vs. All (阈值=0.3)** | **0.967** | 专注的二分类模型将 Bot Recall 提升了 **19 个百分点**。 ### 误差分析 (阈值=0.3) - **总误差:** 173 - **假阴性**(漏掉的 Bot):390 个测试 Bot 中的 **13** 个 - **假阳性**(预测为 Bot,实际为其他类别):**160** - 100% 的假阳性都是 **BENIGN** — 没有任何攻击类别被误判为 Bot - BENIGN 的假阳性率:0.038%(419,010 个中的 160 个) 这种清晰的误差特征使得 Bot vs. All 非常适合作为级联分类器:所有被误分类的样本都是良性流量,而非攻击。 ## 级联分类器 一个两阶段流水线,将 Bot 与其他类别分开处理。 ### 架构 ``` Input flow ↓ [Stage 1 — Bot Detector] threshold=0.3 ↓ ↓ BOT ✓ Not Bot ↓ [Stage 2 — Multi-class RF] ↓ BENIGN / DDoS / PortScan / ... ``` - **阶段 1:** 在所有流量上训练的二分类 RF(200 棵树,max_depth=30,class_weight='balanced') - **阶段 2:** **仅在非 Bot 流量**(12 个类别)上训练的多分类 RF(200 棵树,max_depth=30) ### 结果 | 指标 | 调优后的 RF(单模型) | 级联 | |--------|------------------------|---------| | F1 Macro | 0.9568 | 0.9558 | | **Bot Recall** | 0.771 | **0.961** | | Web Attack Recall | 0.977 | 0.977 | | BENIGN Recall | 0.999 | 0.999 | ### 关键发现 - **Bot Recall 提升了 19 个百分点**(0.771 → 0.961),而对总体 F1 Macro 没有实质性影响(-0.001) - 所有其他类别均未受影响 — 阶段 2 的表现与独立的多分类模型完全相同 - **针对 Bot 的特定 IAT 特征**(`iat_cv`, `fwd_iat_cv`, `small_packet_ratio`)经过了测试但被移除 — 它们仅使 Bot Recall 增加了 +0.003,却使 F1 Macro 降低了 -0.006,并损害了 Infiltration 的召回率 ### 为什么级联有效 在多分类模型中,Bot 容易与 BENIGN 混淆,因为两者都使用 HTTP。二分类的阶段 1 完全专注于学习这种微妙的边界,而阶段 2 则完全摆脱了对 Bot 行为的建模。 ## EDA 图表 #### 标签分布 ![标签分布](https://raw.githubusercontent.com/Iditc/CIC-IDS2017-analysis/main/output/eda/label_distribution.png) #### 相关性热力图 ![相关性热力图](https://raw.githubusercontent.com/Iditc/CIC-IDS2017-analysis/main/output/eda/correlation_heatmap.png) #### 前 6 个最具区分度的特征 ![关键特征分布](https://raw.githubusercontent.com/Iditc/CIC-IDS2017-analysis/main/output/eda/top_features_distribution.png) #### 已删除特征热力图 ![已删除特征热力图](https://raw.githubusercontent.com/Iditc/CIC-IDS2017-analysis/main/output/dropped_features_heatmap.png) ## 异常检测 在仅包含 BENIGN 流量的数据上训练了两个无监督模型,并在所有类别上进行了评估。 ### Isolation Forest 与 Autoencoder 对比 | 类别 | Isolation Forest | Autoencoder | |-------|-----------------|-------------| | BENIGN(假阳性率) | **1.02%** | 5.03% | | Heartbleed | 50% | **100%** | | Infiltration | 29% | **100%** | | DoS Hulk | 12% | **94%** | | DoS Slowhttptest | 8% | **96%** | | DDoS | 0.1% | **72%** | | Bot | 1.8% | 5.1% | | Web Attack | 0% | 4.2% | | **平均 Precision** | 0.50 | **0.83** | **Autoencoder** 显著优于 Isolation Forest。它能够捕捉 BENIGN 流量的非线性特征结构,从而对偏离正常模式的攻击保持敏感。 **Bot 和 Web Attack 无法被任一模型检测到** — 它们故意模拟正常的 HTTP 流量,因此改由有监督的级联模型进行处理。 ## 全模型对比 所有模型均在带有合并后的 Web Attack 标签(13 个类别)的特征工程数据集上进行评估。 | 模型 | F1 Macro | Bot Recall | Web Attack Recall | Heartbleed Recall | |-------|----------|-----------|------------------|------------------| | 基准 RF | 0.9511 | 0.771 | 0.972 | 0.500 | | 平衡 RF (`class_weight='balanced'`) | 0.9572 | 0.774 | 0.974 | 0.500 | | 基准特征工程 | 0.9564 | 0.763 | 0.977 | 0.500 | | 平衡特征工程 | 0.9571 | 0.769 | 0.977 | 0.500 | | 调优后 RF (200 棵树, depth=30) | 0.9568 | 0.771 | 0.977 | 0.500 | | 级联 RF (Bot + 多分类 RF) | 0.9558 | 0.961 | 0.977 | 0.500 | | **级联 LightGBM (Bot + 多分类 LGBM)** | **0.9827** | **0.964** | **0.995** | **1.000** | ## 最终模型 — 级联 LightGBM ### 架构 ``` Stage 1 — Bot Detector (Binary RF, threshold=0.3) Bot → "Bot" else → Stage 2 Stage 2 — Multi-class LightGBM (500 trees, 63 leaves, lr=0.05) Classifies: BENIGN / DoS / DDoS / PortScan / Heartbleed / Infiltration / Web Attack / FTP-Patator / SSH-Patator ``` ### 为什么使用级联? 单一的多分类模型会将 Bot 与 BENIGN 混淆,因为两者都使用 HTTP。二分类的阶段 1 完全专注于区分 Bot 流量的细微模式(PSH 比率、数据包大小的一致性、时间规律性)。阶段 2 则受益于完全不需要对 Bot 进行建模。 ### 为什么选择 LightGBM 而不是 Random Forest? LightGBM 使用梯度提升 — 每棵树都会纠正前一棵树的错误。这对于 RF 难以处理的罕见类别(Heartbleed、Web Attack)尤其有效。在 250 万行数据上,LightGBM 的训练时间约为 10 分钟,而 RF 约为 20 分钟。 ### 最终结果 | 类别 | 基准 RF | 平衡 RF | 级联 RF | **级联 LightGBM** | |-------|------------|------------|-----------|---------------------| | F1 Macro | 0.9511 | 0.9572 | 0.9558 | **0.9827** | | **Bot** | 0.771 | 0.774 | 0.961 | **0.964** | | **Web Attack** | 0.972 | 0.974 | 0.977 | **0.995** | | **Heartbleed** | 0.500 | 0.500 | 0.500 | **1.000** | | Infiltration | 0.857 | 1.000 | 1.000 | **1.000** | | BENIGN | 0.999 | 0.999 | 0.999 | 0.999 | | DDoS | 1.000 | 1.000 | 1.000 | 1.000 | | PortScan | 0.988 | 0.988 | 0.988 | **0.999** | ### 基准测试背景 文献中的 Random Forest 模型在 CIC-IDS2017 上通常达到 F1 Macro ~0.93。我们的级联 LightGBM 达到了 **0.9827** — 显著高于已发布的基准水平。 ### 混淆矩阵 ![级联 LightGBM 混淆矩阵](https://raw.githubusercontent.com/Iditc/CIC-IDS2017-analysis/main/output/models/pipeline/cascade_lgbm_confusion_matrix.png) ### 已知局限性 - **SQL Injection** — 样本非常少(总共约 21 个),使得子类分类不可靠。 - **Web Attack 子** — 当将 Web Attack 拆分为 Brute Force / XSS / SQL Injection 时:Brute Force 的 Recall 达到 0.83,XSS 为 0.31,SQL Injection 为 0.00。样本稀缺是瓶颈所在。
标签:Apex, Python, 代码示例, 数据分析, 无后门, 机器学习, 特征工程, 网络安全, 逆向工具, 隐私保护