2026 年 10 月
在不确定性下做判断 → 输出概率
需要一定数量的历史标注数据
能回答 "有多大概率是恶意"
如果连 "正常/恶意" 的样本都没有呢?
0-day 攻击根本没有历史样本
能发现 "从未见过" 的威胁吗?
🚨 核心转折: 前面的算法都在 "学习规律"。但如果攻击者用的是从未出现过的新手法,规律根本不存在 —— 我们只能靠 "异常" 来发现它。
🎯 孤立森林: 不需要标注、不需要已标注的历史样本 —— 它给每个样本单独打异常分,哪怕只有一个孤点也能抓。
分工: K-Means 找 "成团的未知",孤立森林抓 "孤立的未知"。
某部内网运行正常,每天产生海量流量日志。
已部署基于规则的 IDS,但攻击者使用 0-day 漏洞 进入内网。
规则库中没有该攻击的特征
历史数据中没有标注样本
决策树/贝叶斯无法训练
不需要知道 "恶意" 长什么样
只需要知道 "正常" 长什么样
发现 "不像正常" 的行为 → 异常
🎯 本部分目标: 在没有任何标注样本的情况下,用 "异常即信号" 的思路发现未知威胁。
异常检测 = 在海量数据中发现 "少数派"
大量出现(99%)
彼此相似
符合预期模式
极少出现(1%)
与主流不同
偏离预期模式
💡 网空含义: 0-day 攻击、未知恶意软件、APT 渗透 —— 它们的行为模式一定与 "正常" 不同。找到这个 "不同",就找到了威胁线索。
🔓 0-day 攻击 —— 利用 "刚被发现、厂商还没来得及出补丁" 的漏洞发起的攻击。规则库没有它的特征,也没有历史样本 → 基于已知特征的检测全部失效。
🕵️ APT 渗透 —— Advanced Persistent Threat,高级持续性威胁:攻击者长期潜伏、低频慢速行动,每一步都伪装得 "像正常" → 单条规则抓不住,需要发现 "慢速" 异常。
异常点更容易被 "隔离" 出来。
房间里有 100 个人:
99 个人站在一起(正常群体)
1 个人站在角落(异常个体)
| 直觉 | 算法 |
|---|---|
| 人群聚集 | 正常点:在数据空间中密集分布 |
| 角落孤立 | 异常点:远离数据密集区域 |
| 容易发现 | 路径短:异常点容易被随机切分隔离 |
💡 孤立森林就是把这个直觉变成了算法。 无需标注、无需先验知识,通过随机切分寻找容易被隔离的点。
⬤ ⬤ ⬤ ⬤ ⬤
密集分布 · 相互靠近
▲
远离群体 · 单独存在
密集区域 → 多次随机切分才能分开
⬤⬤⬤⬤⬤ → ⬤⬤ → ⬤ → ✅ 隔离
远离群体 → 随机切分很快单独分离
▲ → ✂ → ✅ 隔离
💡 关键直觉: 异常点远离群体 → 更容易被随机切分 "隔离" 出来 → 路径更短
孤立森林 = 多棵 "孤立树" 的集合
每个节点:随机选一个特征,在该特征的取值范围内随机切一刀(二分)
每个叶子节点 = 一个被隔离的样本
本质:一棵 "随机二分树",不需要任何标签
构建很多棵孤立树(默认 100 棵)
每棵树用不同的随机切分
综合所有树的结果 → 更稳定可靠
💡 类比: 单棵树的判断可能有偏差,但多棵树综合判断就很可靠。这就是 "集成学习" 的思路 —— 集中多人的智慧,比依赖一个人更可靠。
%%{init: { 'theme': 'base', 'themeVariables': { 'fontSize': '17px', 'fontFamily': 'LXGWWenKai, \"Noto Sans SC\", sans-serif' }, 'flowchart': { 'nodeSpacing': 12, 'rankSpacing': 18 } } }%%
flowchart LR
A["📊 原始数据"]
--> B["🎲 随机选特征"]
--> C["✂ 随机选切分点"]
--> D["📦 切分为两组"]
--> E{"是否隔离?"}
E -->|否| B
E -->|是| F["✅ 记录路径长度"]
style A fill:#1a2a3a,stroke:#268bd2,stroke-width:2px,color:#fff
style B fill:#1a2a3a,stroke:#f39c12,stroke-width:2px,color:#fff
style C fill:#1a2a3a,stroke:#f39c12,stroke-width:2px,color:#fff
style D fill:#1a2a3a,stroke:#268bd2,stroke-width:2px,color:#fff
style E fill:#1a2a3a,stroke:#e74c3c,stroke-width:2px,color:#fff
style F fill:#1a2d1a,stroke:#27ae60,stroke-width:2px,color:#27ae60
🔑 关键步骤:
1. 随机选一个特征(每个节点只选一个,不是把每个特征都切一遍)
2. 在该特征的取值范围内随机选一个切分点
3. 将数据分成左右两份
⏱ 终止条件: 样本被完全隔离 → 记录路径长度 否则 → 递归重复上述过程
🌲 上图是一棵孤立树的构建过程 —— 孤立森林 = 重复建 100 棵,每棵树的随机选择都不同;多棵树合起来,所有特征都会被轮到。
一个具体例子:外连频率
| 步骤 | 数据(外连频率,次/小时) | 说明 |
|---|---|---|
| 原始数据 | [2, 3, 3, 4, 5, 5, 6, 7, 8, 25] | 9 台正常(2~8),1 台异常(25) |
| 第 1 刀(随机) | 切在 5 → [2,3,3,4,5,5] | [6,7,8,25] | 异常点仍在右侧组 |
| 第 2 刀(随机) | 切在 7 → [6,7] | [8,25] | 继续切分右侧组 |
| 第 3 刀(随机) | 切在 10 → [8] | [25] | 异常点被单独分离 ✅ |
为什么正常点难切?
位于密集区域(2~8)
周围全是邻居,随机切分很难单独切出一个 👉 需要很多刀才能分开
为什么异常点容易切?
位于稀疏区域(25)
远离所有邻居,随机切分很容易单独切出 👉 少数几刀就能隔离
💡 异常点不是 "被识别" 出来的,而是 "更容易被随机切分孤立" 出来的。
将路径长度转换为 异常得分(0~1):
🔴 得分接近 1 异常可能性高 → 值得深入排查
🟡 得分接近 0.5 边界区域 → 可进一步研判
🟢 得分接近 0 高度正常 → 无需关注
💡 网空含义: 异常得分不是 "是不是恶意",而是 "有多不像正常"。得分越高,越值得深入调查。
import numpy as np
from sklearn.ensemble import IsolationForest
# 1. 生成正常数据(1000 个,集中在原点附近)
normal = np.random.randn(1000, 2)
# 2. 生成异常数据(20 个,远离正常区域)
outliers = np.random.uniform(low=6, high=8, size=(20, 2))
# 3. 合并数据
X = np.vstack([normal, outliers])
# 4. 训练孤立森林
model = IsolationForest(contamination=0.02, random_state=42)
model.fit(X)
contamination 参数: 预期异常比例,这里设为 2% (20/1020 ≈ 2%)
# 1. 预测异常(-1=异常, 1=正常)
pred = model.predict(X)
print(np.unique(pred, return_counts=True))
# 输出: (array([-1, 1]), array([20, 1000]))
# 2. 查看异常得分(值越小越异常)
scores = model.score_samples(X)
print(scores[:10])
# 3. 查看 Top 5 异常点
top5_idx = np.argsort(scores)[:5]
print(f"Top 5 异常索引: {top5_idx}")
print(f"Top 5 异常得分: {scores[top5_idx]}")
关键理解: sklearn 的 score_samples 输出负的异常分,越负越异常;取相反数或归一化后,就对应上一页 0~1 的异常得分(越接近 1 越异常)。
✅ 核心优势
| 优势 | 网空价值 |
|---|---|
| 无需标签 | 不需要标注正常/恶意样本 |
| 发现未知威胁 | 能检测 0-day、新型攻击 |
| 极快 | 海量日志分钟级完成异常筛选 |
| 高维友好 | 可处理数千维特征 |
| 无需先验知识 | 不需要提前知道 "恶意长什么样" |
⚠ 固有局限
| 局限 | 网空应对 |
|---|---|
| 只能发现 "不像正常" | 需要人工研判确认是否为攻击 |
| 无法区分攻击类型 | 只能提供 "可疑候选",不能替代深入分析 |
| 对参数敏感 | 需要根据数据特点调参(contamination 等) |
💡 定位: 孤立森林不是 "判官",而是 "筛选器" —— 从海量数据中圈出少量可疑目标,让专家聚焦。
| 场景 | 孤立森林做什么 | 为什么选它 |
|---|---|---|
| 🚨 0-day 攻击发现 | 从流量中标记行为异常的主机 | 不需要已知攻击样本 |
| 🔗 APT 检测 | 发现长时间潜伏的异常行为链 | 能发现 "慢速" 异常 |
| 📊 日志异常分析 | 从海量日志中筛选可疑条目 | 极快,适合大数据量 |
| 🌐 DNS 隧道检测 | 标记异常的 DNS 请求模式 | 高维特征处理能力强 |
| 🧠 未知恶意软件发现 | 从进程行为中圈出异常 | 不需要恶意软件签名 |
某部内网部署了异常检测系统。 数据: 1 万条流量日志(无任何标注) 已知: 其中可能存在 0-day 攻击的痕迹,但不知道有多少 方案 A: 用决策树训练(需要人工标注数据) 方案 B: 用孤立森林检测(无需标注) 问题: 你选择哪个方案?孤立森林发现异常后,下一步应该做什么?
选择:方案 B(孤立森林)
🎯 核心价值: 孤立森林做 "初筛",专家做 "终判"。从 1 万条聚焦到 10 条,让专家的工作从 "大海捞针" 变成 "精准打击"。
💡 核心思想 异常点更容易被隔离 — 异常即信号
🔑 关键区别 无需标注 — 只需一批 "基本正常" 的数据,不需要任何标签
📊 核心指标 路径长度:异常点路径短,正常点路径长
🎯 网空定位 从 "异常群体" 到 "孤立个体" —— 补上未知威胁的最后一公里
孤立森林不是 "判官",而是 "筛选器" —— 从海量数据中圈出可疑目标,让专家聚焦。
| 遇到的情况 | 任务 | 选用武器 |
|---|---|---|
| 已知威胁,需要可执行的规则 | 分类 | 📜 决策树 |
| 未知威胁,没有标注,找异常群体 | 聚类 | 📏 K-Means |
| 判断概率,辅助决策 | 概率分类 | 🎲 朴素贝叶斯 |
| 从未见过的 0-day | 异常检测 | 🚨 孤立森林 |
一句话记忆: 规则找判据,距离找团伙,概率算风险,孤立抓异常。
今天一起走过四种思维: ✅ 📜 决策树 —— 从 "专家经验" 到 "自动判据" ✅ 📏 K-Means —— 没有答案时,让数据自己 "抱团" ✅ 🎲 朴素贝叶斯 —— 用概率量化不确定性 ✅ 🚨 孤立森林 —— 异常本身就是信号
今天这四种是 "思维原型" —— 具体算法原理的展开,后续课程还会继续深入。
从问题出发选择方法
而不是
从算法出发寻找问题
经典算法的价值,不是让机器替代思考, 而是帮助我们从海量数据中发现规律、 从确定到不确定、从已知到未知。 新技术层出不穷,但经典思想历久弥新。
Q & A