讲师中心 微信公众号
AI工具推荐 视频效率加速

Java序列化与反序列化详细安全指南

云晨同学_9897

云晨同学_9897

发布时间:2025-07-13 10:36:03

|

805人浏览过

|

来源于php中文网

原创

java序列化与反序列化存在安全风险的核心原因在于反序列化不可信数据时可能触发恶意构造的“gadget chains”,从而导致远程代码执行(rce)。1.攻击者可通过精心构造的数据流,利用readobject()方法及反射机制调用危险方法链,例如hashmap结合proxy与invokertransformer实现命令执行;2.解决方案包括:①绝不反序列化不可信来源的数据;②使用java 9引入的objectinputfilter建立白名单机制控制可反序列化的类;③在旧版本中通过继承objectinputstream重写resolveclass实现自定义过滤;④优先采用json、protobuf、avro等替代方案以规避原生序列化风险;⑤定期更新依赖库防止已知漏洞被利用。

Java序列化与反序列化详细安全指南

Java序列化与反序列化,在便利数据传输与持久化的同时,确实埋下了一颗不小的安全隐患。核心问题在于,当一个应用程序从不可信的来源接收并反序列化数据时,攻击者可以精心构造恶意序列化数据,利用Java类库中存在的“gadget chains”(即一系列可被利用的方法调用链),在反序列化过程中触发任意代码执行(RCE)或其他恶意行为。因此,要保障其安全,关键在于严格的输入验证、细致的类白名单控制,以及在可能的情况下,转向更安全的替代方案。

Java序列化与反序列化详细安全指南

解决方案

谈到解决方案,这事儿真不是一蹴而就的,它需要我们从多个维度去思考和实践。首先,最直接也最根本的一点是:永远不要反序列化来自不可信源的数据。这听起来像句废话,但很多时候,我们不自觉地就将外部输入直接送入了反序列化的管道。如果真的非要处理,那么务必引入严格的白名单机制。这不是说简单地检查一下类型,而是要精细到每一个允许被反序列化的类。Java 9引入的ObjectInputFilter是个福音,它提供了一种官方且相对优雅的方式来定义哪些类可以被反序列化。对于老旧的Java版本,我们可能需要自己动手,通过继承ObjectInputStream并重写resolveClass方法来手动实现白名单过滤,这活儿虽然有点儿糙,但效果不错。

立即学习Java免费学习笔记(深入)”;

Java序列化与反序列化详细安全指南

此外,我们还需要审视整个应用架构,看看有没有哪里可以彻底避免使用Java原生序列化。很多时候,我们只是习惯性地用了它,但其实JSON、Protobuf或者Avro等数据格式,在传输和存储方面能提供同样的便利,并且在设计上就规避了原生序列化带来的安全风险。它们通常只关注数据本身的结构化,而不是对象方法的调用。最后,别忘了持续更新你的依赖库,许多已知的反序列化漏洞都与特定版本的第三方库有关,及时修补这些“后门”至关重要。

为什么Java序列化与反序列化会带来安全风险?

Java序列化与反序列化详细安全指南

说实话,Java序列化这个设计,在它诞生的年代,可能没人会想到会演变成今天这样的安全噩梦。它之所以危险,核心在于其机制——当一个对象被反序列化时,ObjectInputStream不仅会重建对象的数据状态,还会调用对象的readObject()方法(如果存在的话),以及通过反射机制实例化对象。问题就出在这里:攻击者可以利用这个特性,构造一个恶意的序列化数据流,这个数据流在反序列化时会触发一系列看似无害,实则环环相扣的方法调用,最终形成一个“gadget chain”。

想象一下,你有一个看似无害的HashMap,但如果它里面装的键值对是经过精心构造的,比如一个键是Proxy对象,值是InvokerTransformer,那么当HashMap在反序列化过程中被重建时,Proxy可能会调用InvokerTransformertransform方法,而这个方法又可以进一步调用任意类的任意方法,比如Runtime.exec(),直接在你的服务器上执行命令。这就是我们常说的“反序列化漏洞”的本质:它不是代码逻辑上的错误,而是对序列化机制的滥用,将数据变成了可执行的指令。Apache Commons Collections库中发现的漏洞就是典型的例子,利用了其内部的一些工具类,实现了远程代码执行。这种攻击的隐蔽性在于,它利用的是合法的方法调用,只是这些调用的组合方式超出了预期的安全边界。

如何有效地防范Java反序列化攻击?

防范Java反序列化攻击,我觉得最关键的是要从“不信任任何外部输入”这个基本原则出发。具体到实践层面,有几个策略是立竿见影的。

Facebook
Facebook

通过 Facebook Graph API 管理页面、帖子、评论、消息和洞察,适用于发布内容或读取互动数据等需求。

下载

首先,也是我个人认为最值得推广的,就是利用Java 9及更高版本提供的ObjectInputFilter。这东西简直就是为解决反序列化安全问题而生的。你可以用它来定义一个白名单,明确告诉JVM只有哪些类是允许被反序列化的。任何不在白名单里的类,哪怕是恶意构造的,也无法被成功反序列化,从而阻断了攻击链。

这里给大家一个简单的示例,看看如何使用ObjectInputFilter来限制允许反序列化的类:

import java.io.ObjectInputFilter;
import java.io.ObjectInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.Serializable;

// 假设我们只允许这个MyDataClass被反序列化
class MyDataClass implements Serializable {
    private static final long serialVersionUID = 1L;
    String name;
    int value;

    public MyDataClass(String name, int value) {
        this.name = name;
        this.value = value;
    }

    @Override
    public String toString() {
        return "MyDataClass{name='" + name + "', value=" + value + "}";
    }
}

// 假设有一个不允许被反序列化的恶意类(攻击者可能尝试注入)
class MaliciousClass implements Serializable {
    private static final long serialVersionUID = 1L;
    String command;

    public MaliciousClass(String command) {
        this.command = command;
    }

    // 恶意构造的readObject方法,可能触发RCE
    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        System.out.println("MaliciousClass readObject called! Executing: " + command);
        // Runtime.getRuntime().exec(command); // 真实的攻击会在这里
    }
}

public class DeserializationFilterExample {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 模拟一个序列化的MyDataClass
        byte[] goodData = serialize(new MyDataClass("safe data", 123));

        // 模拟一个序列化的MaliciousClass
        byte[] badData = serialize(new MaliciousClass("rm -rf /"));

        // 1. 使用ObjectInputFilter进行白名单过滤
        System.out.println("--- Using ObjectInputFilter (Whitelist) ---");
        try (ByteArrayInputStream bis = new ByteArrayInputStream(goodData);
             ObjectInputStream ois = new ObjectInputStream(bis)) {

            // 设置过滤器:只允许MyDataClass及其内部类型(如String, int)通过
            ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(
                "java.base/*;com.example.MyDataClass;!*" // 允许java.base下的所有,允许MyDataClass,拒绝其他所有
            );
            ois.setObjectInputFilter(filter);

            MyDataClass obj = (MyDataClass) ois.readObject();
            System.out.println("Successfully deserialized: " + obj);

        } catch (Exception e) {
            System.err.println("Deserialization failed for good data (unexpected): " + e.getMessage());
        }

        try (ByteArrayInputStream bis = new ByteArrayInputStream(badData);
             ObjectInputStream ois = new ObjectInputStream(bis)) {

            ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(
                "java.base/*;com.example.MyDataClass;!*"
            );
            ois.setObjectInputFilter(filter);

            System.out.println("Attempting to deserialize malicious data...");
            Object obj = ois.readObject(); // 这里会抛出异常
            System.out.println("Unexpectedly deserialized: " + obj);

        } catch (java.io.InvalidClassException e) {
            System.err.println("Successfully blocked malicious class: " + e.getMessage());
        } catch (Exception e) {
            System.err.println("Deserialization failed for malicious data: " + e.getMessage());
        }

        // 2. 不使用过滤器(模拟旧版本或未配置的情况)
        System.out.println("\n--- Without ObjectInputFilter ---");
        try (ByteArrayInputStream bis = new ByteArrayInputStream(badData);
             ObjectInputStream ois = new ObjectInputStream(bis)) {
            System.out.println("Attempting to deserialize malicious data without filter...");
            Object obj = ois.readObject(); // 此时MaliciousClass的readObject会被调用
            System.out.println("Deserialized (potentially dangerous): " + obj);
        } catch (Exception e) {
            System.err.println("Deserialization failed without filter (unexpected): " + e.getMessage());
        }
    }

    // 辅助方法:将对象序列化为字节数组
    private static byte[] serialize(Serializable obj) throws IOException {
        java.io.ByteArrayOutputStream bos = new java.io.ByteArrayOutputStream();
        java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(bos);
        oos.writeObject(obj);
        oos.flush();
        return bos.toByteArray();
    }
}

其次,对于那些还在使用Java 8或更早版本的项目,或者需要更细粒度控制的场景,我们可以通过继承ObjectInputStream并重写resolveClass方法来实现自定义的类加载过滤。这个方法会在反序列化过程中尝试加载类时被调用,你可以在这里加入自己的判断逻辑,如果发现尝试加载的类不在你的白名单里,就直接抛出ClassNotFoundException。这虽然比ObjectInputFilter麻烦点,但效果同样显著。

最后,一个往往被忽视但极其重要的点是:定期审查和更新你的第三方依赖。许多反序列化攻击利用的“gadget chains”都存在于流行的开源库中,比如Apache Commons Collections、Spring Framework等。这些库一旦被发现漏洞并发布了补丁,我们就应该立即升级。使用像OWASP Dependency-Check这样的工具,可以帮助你自动化这个过程,发现项目中存在的已知漏洞依赖。

在现代Java应用中,有哪些更安全的序列化替代方案?

在我看来,如果你正在开发新的Java应用,或者有机会重构现有系统的某个模块,那么真的可以认真考虑一下Java原生序列化的替代方案。这些替代方案通常在设计之初就考虑到了跨语言、数据格式清晰等特性,并且在安全性上提供了更好的保障,因为它们往往不涉及任意代码执行的能力。

最常见且广泛使用的是JSON (JavaScript Object Notation)。搭配Jackson或Gson这样的库,JSON几乎成了Java应用间数据交换的标准。它的优点是人类可读性强、易于调试,并且在反序列化时,通常只负责将JSON数据映射到Java对象的字段,不会像原生序列化那样自动调用复杂的readObject方法。当然,使用JSON时也要注意,比如Jackson库的enableDefaultTyping功能,如果使用不当,也可能引入安全风险,因为它允许JSON数据中指定Java类型,从而可能被利用进行类加载攻击。但相比原生序列化,其攻击面已经大大缩小。

然后是Protocol Buffers (Protobuf)。这是Google开发的一种语言无关、平台无关、可扩展的数据序列化格式。它通过定义.proto文件来描述数据结构,然后生成对应语言的源代码,强制了数据的强类型和结构化。这种模式天生就比Java原生序列化安全得多,因为反序列化过程是基于严格的模式定义的,不会有“意外”的方法调用。它的优点是序列化后的数据体积小、解析速度快,非常适合高性能的RPC通信场景。

再者是Apache Avro。Avro是Hadoop生态系统中广泛使用的一种数据序列化系统。它也使用JSON来定义数据模式,但序列化后的数据是二进制的,紧凑且高效。与Protobuf类似,Avro也是模式驱动的,这意味着在反序列化时,系统知道数据的确切结构,同样避免了因类型不确定性而引发的潜在安全问题。它特别适合大数据场景下的数据持久化和传输。

除了这些,还有一些其他的选择,比如MessagePack(一种高效的二进制序列化格式,可以看作是二进制的JSON)、Apache Thrift(Facebook开源的RPC框架,也包含序列化协议)等。它们的核心思想都是将数据的序列化和反序列化过程与具体的对象行为解耦,专注于数据的结构化表示,从而避免了Java原生序列化中那种“数据即代码”的潜在危险。选择哪一种,往往取决于你的具体需求:是需要人类可读性,还是极致的性能和数据紧凑性,亦或是跨语言互操作性。但无论如何,它们都比原生序列化在安全性上迈进了一大步。

热门AI工具

更多
讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

二狗PPT
二狗PPT Hot

一款AI演示文稿工具,主要用于专为中式职场打造的AI PPT生成工具,适合需要提升相关任务效率的用户。

Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

Seko
Seko Hot

一款AI视频创作工具,主要用于商汤科技推出的创编一体的AI短视频创作Agent,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

相关专题

更多
spring框架介绍
spring框架介绍

本专题整合了spring框架相关内容,想了解更多详细内容,请阅读专题下面的文章。

2131

2025.08.06

Java Spring Security 与认证授权
Java Spring Security 与认证授权

本专题系统讲解 Java Spring Security 框架在认证与授权中的应用,涵盖用户身份验证、权限控制、JWT与OAuth2实现、跨站请求伪造(CSRF)防护、会话管理与安全漏洞防范。通过实际项目案例,帮助学习者掌握如何 使用 Spring Security 实现高安全性认证与授权机制,提升 Web 应用的安全性与用户数据保护。

397

2026.01.26

json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

1955

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

2622

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

916

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

2939

2025.09.10

treenode的用法
treenode的用法

​在计算机编程领域,TreeNode是一种常见的数据结构,通常用于构建树形结构。在不同的编程语言中,TreeNode可能有不同的实现方式和用法,通常用于表示树的节点信息。更多关于treenode相关问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2141

2023.12.01

C++ 高效算法与数据结构
C++ 高效算法与数据结构

本专题讲解 C++ 中常用算法与数据结构的实现与优化,涵盖排序算法(快速排序、归并排序)、查找算法、图算法、动态规划、贪心算法等,并结合实际案例分析如何选择最优算法来提高程序效率。通过深入理解数据结构(链表、树、堆、哈希表等),帮助开发者提升 在复杂应用中的算法设计与性能优化能力。

296

2025.12.22

Buffalo框架数据库开发全教程
Buffalo框架数据库开发全教程

本专题围绕Buffalo框架数据库开发,讲解database.yml多环境配置、soda与fizz迁移生成回滚、模型结构体标签、增删改查与条件查询、一对多与多对多关联、数据校验、回调钩子、事务处理及原生SQL执行能力。

20

2026.09.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Apache Maven 官方安装指南
Apache Maven 官方安装指南

共0课时 | 0人学习

Apache Maven 官方用户中心
Apache Maven 官方用户中心

共0课时 | 0人学习

Apache Subversion 官方手册
Apache Subversion 官方手册

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn