从原理到防御实战
目录导读
- 什么是序列化与反序列化?
- 反序列化漏洞的核心成因是什么?
- 典型攻击场景与代码示例
- 为什么现代应用仍频繁中招?
- 如何有效防御反序列化攻击?
- 常见问题问答(FAQ)
什么是序列化与反序列化?
序列化是将内存中的对象状态转换为可存储或传输的格式(如二进制、XML、JSON、YAML等)的过程,反序列化则是逆向过程——将字节流还原为内存对象,这一机制在分布式系统、缓存(如Redis序列化存储)、远程调用(RPC)、会话管理(如Java的Session序列化)等场景中被广泛使用。

关键点:反序列化本质上信任了外部输入,认为字节流是“安全且合法的”。
反序列化漏洞的核心成因是什么?
反序列化漏洞的核心成因可归纳为两点:
魔术方法自动触发
很多语言的反序列化机制在恢复对象时,会自动调用对象的特定魔术方法(如PHP的__wakeup()、__destruct();Java的readObject()、readResolve();Python的__reduce__()、__setstate__()等),攻击者通过构造恶意对象,让这些方法执行危险操作,如执行系统命令、文件读写、网络请求等。
对象注入与任意类加载
攻击者可以传入任意类的序列化数据,如果应用中没有对反序列化的类进行白名单校验,攻击者就能利用“可利用的类”(常被称为反序列化利用链,如Apache Commons Collections中的InvokerTransformer类)串联多个方法的调用,最终实现远程代码执行(RCE)。
通俗解释:就像你收到一个“完全信任”的快递包裹,没有检查里面是什么就打开,结果里面的“木马玩具”一碰就自己启动了炸弹。
典型攻击场景与代码示例
以PHP反序列化漏洞为例
// 存在漏洞的类
class Test {
public $payload = "";
public function __wakeup() {
eval($this->payload); // 危险!直接执行传入的代码
}
}
// 攻击构造
$malicious = new Test();
$malicious->payload = "system('whoami');";
print(serialize($malicious));
// 输出类似:O:4:"Test":1:{s:7:"payload";s:15:"system('whoami');";}
// 当反序列化这个字符串时,__wakeup() 自动调用,执行系统命令
Java反序列化利用链举例
攻击者利用Apache Commons Collections库中的InvokerTransformer,配合TransformedMap、LazyMap等类,通过反射调用Runtime.getRuntime().exec()。
为什么现代应用仍频繁中招?
- 中间件默认配置:如JBoss、WebLogic、Jenkins等曾默认开启反序列化接口,未做安全检查。
- 框架滥用:Fastjson、Jackson等JSON库在处理特殊类型(如
@type)时,允许指定类名反序列化。 - 安全认知不足:许多开发者误以为数字签名或简单校验就能防御,实际上攻击者可以绕过签名或构造合法签名的恶意对象。
如何有效防御反序列化攻击?
| 防御层级 | 具体措施 |
|---|---|
| 输入校验 | 使用白名单限制允许反序列化的类名,拒绝所有未注册类 |
| 数据类型判断 | 对JSON/XML等格式采用严格schema校验,禁止动态类型指定 |
| 魔法方法监控 | 在开发框架层禁用或重写危险魔术方法(如__wakeup) |
| 使用替代格式 | 尽量使用纯数据格式(JSON不带@type、Protocol Buffers) |
| 运行沙箱隔离 | 在低权限容器中运行反序列化逻辑 |
| 及时打补丁 | 升级库版本(如升级Jackson至2.10+,禁用默认类型反序列化) |
常见问题问答(FAQ)
问:是不是所有反序列化操作都有漏洞?
答:否,漏洞主要出现在:1)反序列化内容来自外部不可信源;2)反序列化过程中会调用对象的魔术方法;3)存在已知的利用链组件。
问:数字签名可以完全防御反序列化攻击吗?
答:不能,签名只能保证数据未被篡改,但不能防止攻击者使用合法签名来传输恶意构造的对象(因为对象内部结构可以完全符合序列化规范)。
问:用JSON代替原生二进制序列化是否安全?
答:不一定,Fastjson、Jackson等库支持自动类型绑定时,如果允许@type指定类名,同样存在反序列化攻击入口。
问:发现反序列化漏洞后应该如何应急响应?
答:立即隔离受影响服务,阻断入站反序列化流量;审查日志中异常类名(如Runtime、ProcessBuilder、InvokerTransformer等);回滚至安全版本或应用临时白名单层。
总结一句话:反序列化漏洞的本质在于“信任了不可信任的数据,并自动触发了不可控的行为”,只有从输入、中间处理、输出全链路限制,才能真正封堵漏洞。