决策树 · Decision Tree


从 "专家经验" 到 "自动判据" 的桥梁

网空关键词:恶意流量判据提取 · 告警规则自动生成 · 白盒可解释

南京大学计算机学院    杨已彪

计算机软件新技术全国重点实验室

yangyibiao@nju.edu.cn

2026 年 10 月

一个网空场景

某部物理隔离内网,监测节点持续上报流量特征

判定某条外连请求是否为 恶意 C2 通信?

(C2 = Command & Control, 指挥与控制: 木马与攻击者之间的远程指令通道。发现 C2 通信,就是发现被控主机。)

🎯 检测重点不是 "谁连进来",而是 "谁在频繁向外发可疑信号"。

(物理隔离 ≠ 零外联: 补丁分发、DNS 解析等少数受控通道仍在, 木马借道主动外连)

攻击者如何进来? 如何藏?

要抓住 C2 通信,先看清这条链路的起点:攻击者如何进来、如何藏身。

🔓 入侵路径(已发生案例)

  • 通过 U 盘摆渡 植入(震网病毒)

  • 通过 固件预置后门 植入

  • 通过 供应链攻击 植入

  • 通过 运维通道 渗透

🕵️‍♂️ 藏身与通联(C2)

  • 藏身: 伪装成合法协议(HTTPS/DNS)

  • 藏身: 利用正常软件更新通道

  • 通联: 通过加密隧道传输指令

  • 通联: 低频心跳长期潜伏

💡 藏得再深,也必须向外通联 —— 而外联必然留下流量特征。下一节:用决策树把这些蛛丝马迹变成判定规则。

决策树的核心思想

不断提问,逐层判定。以流量检测为例:

%%{init: { 'themeVariables': { 'fontSize': '18px' }, 'flowchart': { 'nodeSpacing': 16, 'rankSpacing': 24 } } }%%
flowchart TD
    A["📡 外连请求 · 20 条<br/>(10 正常 / 10 恶意)"]
    --> B["❓ 端口 = 443 ?<br/>(10 正常 / 10 恶意)"]
    B -->|否| C["❓ 频率 > 10/min ?<br/>(2 正常 / 6 恶意)"]
    B -->|是| D["❓ 载荷 > 1400B ?<br/>(8 正常 / 4 恶意)"]
    C -->|是| E["🔴 恶意 C2<br/>(0 正常 / 6 恶意)"]
    C -->|否| F["🟢 正常<br/>(2 正常 / 0 恶意)"]
    D -->|是| G["❓ 间隔 < 5s ?<br/>(2 正常 / 4 恶意)"]
    D -->|否| H["🟢 正常<br/>(6 正常 / 0 恶意)"]
    G -->|是| I["🔴 恶意 C2<br/>(0 正常 / 4 恶意)"]
    G -->|否| J["🟢 正常<br/>(2 正常 / 0 恶意)"]
    style A fill:#dceaf5,stroke:#268bd2,stroke-width:2px,color:#073642
    style B fill:#f7e5d4,stroke:#cb4b16,stroke-width:2px,color:#073642
    style C fill:#f7e5d4,stroke:#cb4b16,stroke-width:2px,color:#073642
    style D fill:#f7e5d4,stroke:#cb4b16,stroke-width:2px,color:#073642
    style G fill:#f7e5d4,stroke:#cb4b16,stroke-width:2px,color:#073642
    style E fill:#f7dcdc,stroke:#dc322f,stroke-width:2px,color:#dc322f
    style I fill:#f7dcdc,stroke:#dc322f,stroke-width:2px,color:#dc322f
    style F fill:#e3eed4,stroke:#859900,stroke-width:2px,color:#859900
    style H fill:#e3eed4,stroke:#859900,stroke-width:2px,color:#859900
    style J fill:#e3eed4,stroke:#859900,stroke-width:2px,color:#859900

节点括号内 = (正常 / 恶意) 条数 —— 沿 "是/否" 一路走到叶子,占比就是判定的把握

本质: 自动寻找 "最有价值的问题",形成判定链条。

什么是 "好特征"?

网空场景: 某内网采集了 1000 条外连(出站连接)日志(500 正常 + 500 恶意)

(注: 1:1 仅为便于对比好坏特征;真实外连日志中恶意占比通常 <1% ——"恶意样本极度稀少"正是第五部分孤立森林要解决的问题)

✅ 好特征: 目标端口是否为 443 ?

左: 450 恶意 + 50 正常 右: 50 恶意 + 450 正常

→ 一刀下去,恶意与正常基本分开

❌ 差特征: 协议是否为 TCP ?

左: 250 恶意 + 250 正常 右: 250 恶意 + 250 正常

→ 两边一样混杂,等于没分

好特征 = 能把 "混杂" 快速降为 "纯净"

💡 单个特征很少能一锤定音 —— 决策树的价值,在于把多个好特征串成判定链(如上页: 端口 → 载荷 → 间隔)。

熵 · 衡量 "混乱程度"

📐 公式 + 小例子

\[ H=-\sum p_i \log_2 p_i \]

例: 10 条流量中 7 条正常、3 条恶意 \[ H=-(0.7\log_2 0.7+0.3\log_2 0.3) \] \[ =0.36+0.52\approx 0.88 \]

📊 直观理解
数据状态 熵值
全是正常流量 0(纯净)
正常/恶意各半 最大(混乱)
7 正常 / 3 恶意 ≈ 0.88(中间)
全是恶意流量 0(纯净)

💡 网空含义: 熵越低,规则越精准,误报越少。

信息增益 · 特征 "好" 的量化指标

定义: \[ Gain(D, A) = H(D) - \sum_{v} \frac{|D_v|}{|D|}\, H(D_v) \]

(\(A\) = 待选特征; \(D_v\) = 按 \(A\) 取值 \(v\) 分出的分支 —— 划分后的熵按各分支大小加权平均)

划分效果 信息增益
划分后仍然混乱 小
划分后非常纯净 大

翻译成人话: 划分前多乱,划分后多不乱 —— 差值越大,这个特征越值得用。

决策树家族 · 时间线

%%{init: { 'theme': 'base', 'themeVariables': { 'fontSize': '20px', 'fontFamily': 'LXGWWenKai, \"Noto Sans SC\", sans-serif' }, 'flowchart': { 'nodeSpacing': 30, 'rankSpacing': 35 } } }%%
flowchart TB
    A["CART<br/>1984"]
    --> B["ID3<br/>1986"]
    --> C["C4.5<br/>1993"]
    --> D["Random Forest<br/>2001"]
    --> E["XGBoost<br/>2014"]
    style A fill:#1a2a3a,stroke:#586e75,stroke-width:2px,color:#839496
    style B fill:#1a2a3a,stroke:#268bd2,stroke-width:2px,color:#fff
    style C fill:#1a2a3a,stroke:#268bd2,stroke-width:2px,color:#fff
    style D fill:#1a2a3a,stroke:#586e75,stroke-width:2px,color:#839496
    style E fill:#1a2a3a,stroke:#586e75,stroke-width:2px,color:#839496
算法 年份 核心逻辑
ID3 1986 选择信息增益最大的特征
C4.5 1993 使用 "增益率"

🎯 本课程重点: ID3(理解原理)+ C4.5(工业常用)

ID3 的问题:偏爱 "取值多" 的特征

场景接上文: 1000 条外连日志,每条 Log ID 唯一。若交给 ID3 选划分特征,它会选中谁?

❌ Log ID · 1000 个取值

1000 个分支,每支恰好 1 条 → 每支都纯净(熵 = 0)

信息增益 最大,ID3 一定选它

但新日志的 ID 从未见过 → 无法归类,"背答案" 而已

✅ 目标端口 · 少量取值

几个分支,每支仍有混杂(熵 > 0)

信息增益 中等,ID3 看不上它

但新流量按端口照样判定 → 真正 "学会"

🎯 根源: 信息增益只奖励 "切得纯",不奖励 "切得有用"。 取值越多越容易切纯 → ID3 偏爱取值多的特征 → 过拟合

C4.5 的改进:增益率

增益率 = 信息增益 ÷ 惩罚项 IV \[ GainRatio(A) = \frac{Gain(D, A)}{IV(A)},\qquad IV(A) = -\sum_{v} \frac{|D_v|}{|D|} \log_2 \frac{|D_v|}{|D|} \]

(IV = 特征自身取值的 "分散程度",就是特征取值分布的熵:取值越多 → IV 越大 → 惩罚越重)

特征 信息增益 IV(惩罚) 增益率 效果
Log ID 最大 最大 ⬇ 被压低 不再被误选
目标端口 中等 小 ⬆ 相对更高 公平竞争

类比: ID3 是第一代预警系统,容易被 "花哨" 特征欺骗; C4.5 是第二代,加了 "公平性检查",更可靠。

ID3 与 C4.5

算法 核心逻辑 特点
ID3 选择信息增益最大的特征 奠基,但偏好取值多的特征
C4.5 使用 "增益率" 支持连续值/缺失值,工业更常用

网空落地: 流量特征多为连续值(频率、包长),日志常有缺失字段 —— C4.5 的这两项能力,正是它比 ID3 更适合实战的原因。

决策树如何生成检测规则?

从历史数据中自动提取判据的五个步骤

%%{init: { 'theme': 'base', 'themeVariables': { 'fontSize': '20px', 'fontFamily': 'LXGWWenKai, \"Noto Sans SC\", sans-serif' }, 'flowchart': { 'nodeSpacing': 16, 'rankSpacing': 24 } } }%%
flowchart LR
    A["📡 已标注数据"]
    --> B["🔍 找最佳特征"]
    --> C["⚙ 生成规则"]
    --> D["🌿 构建完整树"]
    --> E["✅ 输出判据链"]

步骤详解:历史流量日志(已标注) → 选择最佳判据特征(信息增益最大) → 按阈值切分生成规则节点 → 递归生成子规则构建完整树 → 输出白盒可追溯的判据链

❓ 标注数据从哪来? 开源威胁情报: VirusTotal、AbuseIPDB 等已标注的 IP/域名黑名单 · 公开数据集: CIC-IDS、UNSW-NB15 等带有攻击标签的流量数据集 · 历史告警日志:安全分析师已确认的告警记录

⚠ 标注数据是监督学习的前提。数据质量 > 算法选择。

Sklearn 实践 · 核心代码

from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
# 1. 生成模拟数据(10 维特征, 2000 样本)
X, y = make_classification(n_samples=2000, n_features=10,
                           n_informative=6, random_state=42)
# 2. 划分训练/测试集
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42)
# 3. 训练决策树(限制深度防过拟合)
model = DecisionTreeClassifier(max_depth=5, random_state=42)
model.fit(X_train, y_train)
# 4. 评估
print(f"Accuracy = {model.score(X_test, y_test):.4f}")
典型输出:Accuracy = 0.8833

核心优势 · 可解释性

from sklearn.tree import export_text
rules = export_text(model, feature_names=[
    f'feature_{i}' for i in range(10)
])
print(rules)

输出:

|--- feature_3 <= 0.75
|   |--- feature_7 <= -0.23
|   |   |--- class: 0
|   |--- feature_7 > -0.23
|   |   |--- feature_1 <= 0.45
|   |   |   |--- class: 1
|   |   |--- feature_1 > 0.45
|   |   |   |--- class: 0
|--- feature_3 > 0.75
|   |--- feature_5 <= 0.32
|   |   |--- class: 1
|   |--- feature_5 > 0.32
|   |   |--- class: 0

每条规则都可追溯: 为什么拦截这个 IP ? —— 因为满足规则链 A → B → C。

决策树 · 优缺点(网空视角)

✅ 优点
优势 网空含义
易理解 一线人员可直接执行
可解释 指挥员知道 "为什么"
推理快 毫秒级,适合端侧部署
无需 GPU 边缘节点可直接运行
⚠ 缺点
劣势 应对策略
易过拟合 限制深度 + 剪枝
对噪声敏感 集成方法平滑
稳定性差 随机森林/XGBoost

💡 网空启示: 深度学习做 "看得准",决策树做 "说得清、跑得快"。战场需要的是 确定性 > 准确率。

决策树在网空领域的典型应用

场景 决策树做什么
🚨 入侵检测 从流量特征提取可执行判据
🎯 钓鱼 URL 识别 生成 "如果是 → 则拦截" 的规则链
🧠 告警降噪 判断哪些告警真正值得关注
🔗 攻击链还原 逐层判定每个环节的恶意概率
📋 合规审计 提供白盒可追溯的判定依据

随堂思考题

某部内网部署流量检测系统。 方案 A: 深度学习模型(准确率 92%,黑盒) 方案 B: 决策树模型(准确率 87%,白盒) 作为技术负责人,你倾向哪个?为什么?

参考答案 · 决策树的价值在哪?

考量维度 深度学习 决策树
准确率 ✅ 略高 ⚠ 略低
可解释性 ❌ 黑盒 ✅ 完全透明
审计追溯 ❌ 无法追溯 ✅ 每条规则可追溯
一线执行 ❌ 依赖专家解读 ✅ 直接可操作
部署门槛 ❌ 需 GPU 集群 ✅ 单机/边缘可跑
合规要求 ⚠ 难通过 ✅ 天然满足

网空核心命题: 我们要的是 "确定性的可执行规则",而非 "概率性的黑盒判断"。

本部分总结 · 决策树

💡 核心思想

用 "最好的问题" 逐层切分数据

🔑 灵魂指标

信息增益 = 混乱减少的程度

⚖️ ID3 → C4.5

增益率压住 "取值多" 的偏爱,工业更常用

✅ 网空定位

规则透明可执行 —— 从 "专家经验" 到 "自动判据" 的桥梁

💡 规则 ≠ 替代专家 · 规则 = 固化专家经验

下一部分预告

📏 K-Means · 让数据自己 "抱团"
当你不确定恶意行为 "长什么样" 的时候