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 图表
#### 标签分布

#### 相关性热力图

#### 前 6 个最具区分度的特征

#### 已删除特征热力图

## 异常检测
在仅包含 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** — 显著高于已发布的基准水平。
### 混淆矩阵

### 已知局限性
- **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, 代码示例, 数据分析, 无后门, 机器学习, 特征工程, 网络安全, 逆向工具, 隐私保护