特征匹配能抓住「见过的」,抓不住「换个写法的」。 误报和漏报不可能同时为零,这是所有检测系统的宿命。
防火墙按「地址和端口」放行,它不知道放过去的包里装的是什么。 IDS 就是补这一块的:它不拦路,只盯着看。 Demo 用五条特征跑七段流量,看漏在哪、误在哪,再改个参数看能救回多少。
一、两条完全不同的思路
检测入侵有两套办法,思路正好相反:
| 思路 | 怎么做 | 强项 | 软肋 |
|---|---|---|---|
| 特征匹配 | 比对已知的坏字符串 | 误报低 | 新攻击抓不到 |
| 异常检测 | 先学正常,再看谁不像 | 能抓没见过的 | 误报高 |
第一行是主流,因为它的结论好解释:报警时能直接说「它命中了这条规则」,运维一看就懂。 但它的前提很硬: 必须有人先见过这种攻击,把它写进特征库。 所以它对「零日」完全无效——第一天出现的攻击,特征库里一定没有。 第二行听着更聪明,落地却很难:「正常」这件事本身没法定义, 一个每天有新业务的网络,天天都在「异常」。 所以现实中的产品是把两者混着用: 特征负责「已知的、必须抓的」,异常负责「冒个头提醒你去看一眼」。
二、三种绕过手法
特征匹配的对手不是「更强的攻击」,是「换个写法」。
手法只有三类,但每一类都很难防。
第一类是编码。
把 ../ 写成 %2E%2E%2F,服务器收到后会解码再处理,IDS 看到的是没解码的原文。
两边对同一串字节的理解不一样,检测就漏了。
这个现象有个名字,叫解析器差异,它是绕过检测最经典的手法的根。
第二类是拆分。
把攻击字符串拆到两个包里,第一个包发 un,第二个包发 ion select。
如果 IDS 只看单个包、不做重组,它就永远看不见完整的特征。
所以好的 IDS 必须做流重组,而重组又要耗内存、要考虑乱序和超时。
第三类是变慢。
把一次扫描拉长到几天,每个包之间隔几十秒。
任何「单位时间内次数超阈值就报警」的规则都会失效,因为阈值是按秒算的。
这类攻击在日志里看不出来,只能靠「跨天长周期的基线」发现——这也是为什么日志要留那么久。
三、IDS 和 IPS,一字之差
IDS 只报警,IPS 会当场阻断。 这一个字的差别,带来的是完全不同的责任。 报警错了,代价是有人白跑一趟;阻断错了,代价是业务断了。 所以 IPS 的规则必须更保守,宁可漏也不能误杀,而 IDS 可以激进一点,多报几条让人去筛。 部署位置也完全不同:IDS 挂在镜像口上,只看不改,断网也不影响业务; IPS 必须串在链路里,它一挂,业务就断。 所以 IPS 一定要有 bypass,也就是「自己出故障时自动短路」的能力。 最后一个判断值得记住:「误报率」和「漏报率」不可能同时为零。 想少漏,就把阈值放松,误报就多;想少误报,就收紧,漏报就多。 这不是产品做得好不好的问题,是检测这件事的数学性质—— 任何一个二分类器,都只能在两个错误之间选一个位置。
四、动手 Demo:特征匹配的检出率,取决于攻击者会不会换个写法
五条特征、七段流量(四段恶意),先按区分大小写跑一遍,再改成不区分跑一遍。
SIGS = ["../", "<script>", "union select", "/etc/passwd", "cmd.exe"]
TRAFFIC = [
("普通穿越", "GET /../../etc/passwd HTTP/1.1", True),
("穿越做了编码", "GET /%2e%2e%2f%2e%2e%2fetc/passwd", True),
("普通注入", "GET /q?id=1 union select pwd", True),
("注入改大写", "GET /q?id=1 UNION SELECT pwd", True),
("正常文章", "GET /post?title=<script>入门", False),
]
def scan(s, ci):
hit = []
for sig in SIGS:
if (sig.lower() in s.lower()) if ci else (sig in s):
hit.append(sig)
return hit
for name, payload, bad in TRAFFIC:
print(name, bad, scan(payload, False), scan(payload, True))
实跑输出:
--------------------------------------------------------------------
特征匹配的检出率,取决于攻击者会不会换个写法
--------------------------------------------------------------------
**IDS 最常见的一种做法是特征匹配**:**准备一串「坏字符串」,流量里出现了就报警。**
**下面五条特征、七段流量,其中四段是恶意的。**
序 特征
----------------------
1 `../`
2 `<script>`
3 `union select`
4 `/etc/passwd`
5 `cmd.exe`
流量 真的恶意吗 IDS 怎么说 命中的特征
----------------------------------------------------------------------
正常首页 **否** **放过** `—`
正常搜索 **否** **放过** `—`
普通穿越 **是** **报警** `../、/etc/passwd`
穿越做了编码 **是** **放过** `—`
普通注入 **是** **报警** `union select`
注入改了大写 **是** **放过** `—`
正常文章带尖括号 **否** **报警** `<script>`
**四段恶意只抓到 2 段,七段流量还错报了 1 段。**
**这个检出率不是调参调得不好,是方法本身的上限。**
**漏掉的第一段只做了一件事:把 `../` 写成 `%2e%2e%2f`。**
**服务器收到后会先解码再处理,而 IDS 看到的是没解码的原文**——
**两边对同一串字节的理解不一样,检测就漏了。**
**这叫「解析器差异」,是绕过检测最经典的手法**,所以现代 IDS 会做多层解码再匹配。
**漏掉的第二段只改了大写**:**`UNION SELECT` 和特征里的 `union select` 差了三对字母的大小写。**
**对数据库来说这两句完全等价,对字符串比较来说完全不同。**
**误报的那段更能说明问题**:**它只是一个讲 `script` 标签的技术文章标题**,
**因为标题里真的写了那对尖括号,就被当成了攻击。**
**所以误报的根源往往不是「特征写错」,而是「这段文本本来就该出现这个字符串」。**
**那把比较改成不区分大小写呢**:
流量 不区分大小写 命中的特征
---------------------------------------------------------
正常首页 **放过** `—`
正常搜索 **放过** `—`
普通穿越 **报警** `../、/etc/passwd`
穿越做了编码 **放过** `—`
普通注入 **报警** `union select`
注入改了大写 **报警** `union select`
正常文章带尖括号 **报警** `<script>`
**检出从 2 段涨到 3 段,但误报一段没少,编码那段照样漏。**
**所以「调参数」能治一种病,治不了另外两种。**
**最后说清 IDS 和 IPS 的分别**:**IDS 只报警,IPS 会当场阻断。**
**报警错了只是烦人,阻断错了就是事故**——**所以 IPS 的规则通常更保守,宁可漏也别误杀。**
**这个「误报与漏报不可能同时为零」的取舍,是所有检测系统的宿命。**
第一张表里有两行漏了:「穿越做了编码」和「注入改了大写」。
四段恶意只抓到两段,而七段流量里还错报了一段。
漏的第一段只是换了个编码,漏的第二段只是改了大写。
攻击者一行代码都没多写,检测率就从百分之百掉到一半。
这就是特征匹配的上限:它比的是一串字符,而字符有无数种等价写法。
误报的那一段更值得琢磨:它只是一个讲 script 标签的技术文章标题,
因为标题里真的出现了那对尖括号,就被当成了攻击。
所以误报的根源往往不是「特征写错了」,而是「这段文本本来就该出现这个字符串」。
把比较改成不区分大小写以后,检出从两段涨到三段,但误报一段没少,编码那段照样漏。
所以「调参数」能治一种病,治不了另外两种——
这也解释了为什么今天的检测越来越依赖行为和上下文,而不是单看字符串。
30 秒实验
- 算一下:如果特征库有一千条规则、每天十亿个包,每条都对每个包做一次子串查找,是多少次比对? (一万亿次)
- 想一下:为什么「拆分到两个包」能让 IDS 漏检?
- 想一下:IPS 为什么必须有 bypass?
常见误区
- 以为「IDS 能抓住所有攻击」。 它抓的是「写得出来的特征」,换个编码就漏。
- 以为「调严一点就安全了」。 误报和漏报是跷跷板,压下一头就抬起另一头。
- 以为「IDS 和 IPS 只是叫法不同」。 一个只看、一个会拦,责任和部署方式完全不同。
自测三问(点开对答案)
1. 特征匹配和异常检测各自的软肋? —— **前者抓不到没见过的,后者误报高**,所以现实中混着用。 2. 什么叫「解析器差异」? —— **服务器会解码后再处理,IDS 看的是原文**,两边理解不一致就漏检。 3. 为什么 IPS 的规则要比 IDS 保守? —— **阻断错了就是业务事故**,宁可漏也不能误杀。下一节看最后一道防线:装在你自己电脑上的那个东西。
- ☐ (本节完,下一节 9.2.3 反病毒/个人防火墙)