前言

在 Java 安全领域,反序列化漏洞是绕不开的核心高危漏洞,它不依赖前端参数、不局限于业务接口,广泛存在于框架、中间件、第三方依赖和自定义代码中。对于 Java 后端开发、安全开发工程师来说,吃透反序列化漏洞的底层原理、成因、利用逻辑、加固方案,既是面试必考题,也是企业代码安全审计、护网排查的核心能力。

本文从基础概念→漏洞原理→核心成因→风险场景→企业级加固代码→面试考点全维度拆解,完全贴合 Java 安全开发实战与面试需求。


一、核心基础:序列化与反序列化

1. 定义

  • 序列化:将Java 对象转换为二进制字节流的过程,用于对象存储、网络传输、缓存持久化;
  • 反序列化:将二进制字节流重新还原为Java 对象的过程,是序列化的逆操作。

2. 核心规则

  1. 只有实现了 java.io.Serializable 接口的对象,才能被序列化 / 反序列化;
  2. 序列化 / 反序列化由 JVM 自动完成,开发者可重写 readObject() 自定义逻辑;
  3. 序列化数据可被人为构造、篡改

3. 基础代码示例

import java.io.Serializable;

// 实现Serializable接口,标记为可序列化
public class User implements Serializable {
    private String username;
    private String password;

    // 重写readObject方法(漏洞核心入口)
    private void readObject(java.io.ObjectInputStream s) throws Exception {
        s.defaultReadObject();
        // 危险逻辑:若此处写入命令执行代码,反序列化时会自动触发
        Runtime.getRuntime().exec("calc");
    }
}

二、Java 反序列化漏洞核心原理

1. 漏洞本质

服务端信任并直接反序列化「用户可控的恶意二进制数据」,触发重写的 readObject() 方法或第三方依赖中的恶意利用链,最终实现远程代码执行(RCE)

2. 完整攻击链路

  1. 攻击者构造恶意序列化字节流(包含命令执行、代码执行逻辑);
  2. 通过接口、Cookie、请求参数将恶意数据发送给 Java 服务端;
  3. 服务端调用原生反序列化 API,将恶意数据还原为对象;
  4. 自动执行 readObject() 方法,触发恶意代码;
  5. 服务器执行命令,攻击者完全控制主机。

3. 本章总结

反序列化本身不是漏洞,「反序列化用户可控的不可信数据」才是漏洞

三、漏洞核心成因

1. 最核心原因:直接反序列化用户可控数据

服务端直接读取前端传入的参数、Cookie、HTTP Body 中的字节流,不做任何校验就执行反序列化。

// 错误写法:直接反序列化前端传入的不可信数据(高危漏洞)
ObjectInputStream ois = new ObjectInputStream(request.getInputStream());
User user = (User) ois.readObject(); // 恶意数据直接触发漏洞

2. 自定义类重写 readObject() 包含危险操作

开发者在重写方法时,写入了 RuntimeProcessBuilder 等命令执行 API,反序列化时自动触发。

3. 第三方依赖存在「反序列化利用链」

这是企业项目最常见的风险点:经典的 Apache Commons Collections(CC 链) 工具包,存在可被利用的反序列化链,几乎所有老 Java 项目都会引入该依赖,攻击者无需自定义恶意类,直接构造链即可触发 RCE。

4. 框架 / 中间件默认开启反序列化功能

主流 Java 框架存在原生反序列化风险:

  • Shiro:RememberMe 功能会自动反序列化 Cookie 中的用户数据;
  • RMI/JNDI:远程调用服务默认支持反序列化;
  • Fastjson/Jackson:历史版本存在自动反序列化漏洞;
  • Weblogic/JBoss/Tomcat:中间件自带反序列化风险点。

5. 无白名单校验,允许任意类反序列化

Java 原生反序列化默认不限制可加载的类,攻击者可构造任意恶意类被 JVM 加载执行。

四、高危风险场景

  • Shiro 权限框架:RememberMe Cookie 反序列化;
  • 远程调用服务:RMI、JNDI、Hessian 接口;
  • 自定义数据传输接口:使用 Java 序列化做接口通信;
  • 缓存 / 会话持久化:Redis、Session 存储序列化对象;
  • 老旧第三方组件:Commons Collections、BeanUtils 等漏洞依赖。

五、企业级安全加固方案

1. 根本方案:禁止反序列化用户可控数据

核心原则:永远不要反序列化前端传入的任何不可信数据这是最彻底、最安全的修复方式,从源头杜绝漏洞。

2. 替代方案:放弃 Java 原生序列化

Java 原生序列化是不安全、冗余、低效的,企业项目推荐替换为安全的序列化格式

  • 文本格式:JSON(Fastjson/Jackson 升级最新版)
  • 二进制格式:Protobuf、Thrift
  • 禁用 Java 原生 ObjectInputStream 做数据传输

3. 强制白名单校验

若必须使用 Java 反序列化,重写 ObjectInputStream,仅允许合法白名单类反序列化,拦截所有恶意类。

4. 升级第三方依赖,修复利用链

  1. 升级 commons-collections 到无漏洞版本;
  2. Shiro 升级到最新版,开启强随机密钥,关闭非必要 RememberMe 功能;
  3. Fastjson/Jackson 升级到最新安全版,开启安全模式;
  4. 卸载老旧、无用的第三方组件。

5. 中间件 / 框架加固

  1. Tomcat/Weblogic:禁用 RMI/JNDI 匿名访问;
  2. Shiro:RememberMe Cookie 加密,密钥长度≥32 位,定期更换;
  3. 禁止在反序列化流程中调用 RuntimeProcessBuilder 等危险函数。

6. 代码审计 + 安全扫描

  1. 全局搜索代码:ObjectInputStreamreadObject()Serializable
  2. 使用漏洞扫描工具排查反序列化风险;
  3. 护网 / 上线前做专项渗透测试。

六、Java 安全面试高频考点

1. 什么是 Java 反序列化漏洞?

答:Java 反序列化漏洞是指服务端直接反序列化用户可控的恶意二进制数据,触发 readObject() 方法或第三方利用链,最终实现远程代码执行(RCE) 的超高危漏洞。

2. 漏洞的核心触发点是什么?

答:反序列化时,JVM 会自动执行类中的 readObject() 方法,若该方法存在危险逻辑,或存在可利用的第三方依赖链,就会触发漏洞。

3. 为什么 Apache Commons Collections 会导致反序列化漏洞?

答:Commons Collections 中存在恶意反序列化利用链(CC 链),攻击者可构造字节流触发链中的代码执行逻辑,无需自定义恶意类,即可实现 RCE。

4. Java 反序列化漏洞的加固方案有哪些?

答:按优先级排序:

  1. 禁止反序列化用户可控数据(根本方案);
  2. 替换为 JSON、Protobuf 等安全序列化格式;
  3. 重写反序列化流,添加类白名单校验
  4. 升级第三方依赖,修复 CC 链、Shiro 等漏洞;
  5. 中间件加固,禁用危险远程调用服务。

5. Shiro RememberMe 反序列化漏洞原理?

答:Shiro 的 RememberMe 功能会自动反序列化 Cookie 中的用户数据,且默认密钥简单易破解,攻击者构造恶意序列化数据写入 Cookie,服务端反序列化时触发 RCE。

七、总结

Java 反序列化漏洞是 Java 生态的顶级高危漏洞,核心风险源于信任不可信数据,攻击链路简单、危害极大,是护网行动、代码审计的必查项。

对于 Java 开发者:

  1. 牢记核心原则:永远不要反序列化前端传入的不可信数据
  2. 优先放弃 Java 原生序列化,使用 JSON 等安全格式;
  3. 必须使用时,强制添加类白名单校验
  4. 定期升级第三方依赖,修复已知利用链。

对于安全工程师:

  1. 重点排查 Shiro、RMI、Commons Collections 等经典风险点;
  2. 代码审计聚焦 ObjectInputStream 和 readObject() 方法。

更多推荐