反序列化风险是什么
反序列化把字节流还原为程序对象,如果数据源不可信、且还原过程中会触发方法调用或类加载,攻击者就能借构造的字节流让程序执行非预期逻辑——从读写文件到远程命令执行。风险的关键在于「数据格式自带行为」:Java 的序列化、PHP 的序列化函数、Python 的 pickle 等在设计上允许对象图重建,而这个过程中调用的方法链会被攻击者利用。防护方向明确:把不可信数据的传输格式换成纯数据格式(JSON 等),必须使用原生序列化时则用白名单限制可还原的类。
基本信息
| 风险类别 | OWASP Top 10 2021 A08 软件与数据完整性失效;CWE-502 |
|---|---|
| 高危函数 | Java ObjectInputStream、PHP unserialize、Python pickle、Ruby Marshal |
| 触发条件 | 类路径中存在可被拼接利用的类,且数据可控 |
| 判断要点 | 数据是否来自用户?是否存在危险类?两者同时出现风险显著 |
| 常见位置 | 会话与令牌、消息队列、缓存、RPC 接口、导入导出与插件 |
| 根治方式 | 改用纯数据格式,或对可还原类型做严格白名单 |
| 组件维度 | 依赖库版本决定可用链的多少,需要同步升级 |
典型场景
- 登录态或令牌用序列化对象存储,客户端可影响其内容
- 消息队列把对象序列化后传递,生产者与消费者跨信任域
- 缓存里存放序列化对象,缓存服务被写入即可注入
- 远程调用接口接收序列化参数,服务端直接反序列化
- 导入导出功能把序列化内容作为文件内容处理
- 插件与规则引擎允许外部传入配置对象
安全替代示例
安全替代示例
Java:改用 JSON(Jackson/Gson)并禁用多态类型解析
PHP:改用 json_decode;必须 unserialize 时用 allowed_classes 白名单
Python:改用 json;避免 pickle.loads(用户输入)
Ruby:避免 Marshal.load;改用 JSON 解析
# 共同点:让传输格式只承载数据,不承载行为
# 迁移要覆盖所有读写该格式的端点,单点改造会留下兼容分支三类入口与对策
| 入口 | 风险来源 | 对策 |
|---|---|---|
| 网络接口参数 | 客户端可直接构造字节流 | 改纯数据格式并做结构校验 |
| 缓存与队列 | 中间组件被写入或被越权访问 | 限制组件访问来源,校验内容 |
| 本地文件与导入 | 文件内容来自外部 | 解析前校验来源与格式 |
| 会话存储 | 客户端可影响会话内容 | 改用签名令牌或服务端存储 |
组件升级可减少可用链,但不能替代代码层改造:应把反序列化入口改为数据格式解析。
排查时先找「谁在解析不可信数据」而不是先看依赖清单:入口定位清楚后,改造范围与验证方式都更明确。