Wrayの知识库 Wrayの知识库
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
  • Java章节编写规范
  • Java基础

  • Java集合

  • Java并发

  • Java IO

    • Java IO概述
    • IO基础

    • 常用IO流

    • 文件与目录操作

    • Java NIO

    • 高级主题

      • RandomAccessFile
      • 内存映射文件MappedByteBuffer
      • 零拷贝
      • BIO-NIO-AIO模型
      • 字符集与乱码
      • 序列化安全与替代方案
        • 1. 反序列化为什么危险
        • 2. 高风险写法
        • 3. 基本防护原则
        • 4. ObjectInputFilter
        • 5. 版本兼容问题
        • 6. 替代方案
          • 6.1 JSON
          • 6.2 Protocol Buffers
          • 6.3 Avro
          • 6.4 Kryo
        • 7. 选型建议
        • 专家实践清单
        • Tips 快问快答
        • 8. 总结
    • 实践与性能优化

    • 面试与设计题

    • IO实践速查

  • JVM

目录

序列化安全与替代方案

Java 原生序列化使用方便,但在生产环境尤其是服务端系统中,安全风险很高。理解这些风险,比会写 ObjectOutputStream 更重要。

# 1. 反序列化为什么危险

反序列化不是简单地把字节变成字段值。Java 在恢复对象时可能触发类加载、对象构造相关逻辑、readObject、readResolve 等机制。

如果应用反序列化了不可信数据,攻击者可能构造恶意字节流,利用 classpath 中某些类的调用链执行危险操作。

这类问题常被称为反序列化漏洞。

# 2. 高风险写法

try (ObjectInputStream input = new ObjectInputStream(request.getInputStream())) {
    Object obj = input.readObject();
}

如果 request.getInputStream() 来自外部用户,这种写法非常危险。

# 3. 基本防护原则

  • 不反序列化不可信输入。
  • 不把 Java 原生序列化暴露在公网接口。
  • 限制可反序列化的类型白名单。
  • 升级依赖,减少已知 gadget 链。
  • 使用 JDK 提供的对象输入过滤机制。
  • 优先选择更安全、可控的序列化格式。

# 4. ObjectInputFilter

Java 提供了 ObjectInputFilter 用于限制反序列化。

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

try (ObjectInputStream input = new ObjectInputStream(source)) {
    input.setObjectInputFilter(filter);
    Object obj = input.readObject();
}

过滤规则可以限制类名、数组大小、对象图深度、引用数量等。即使使用过滤,也不意味着可以放心处理任意不可信数据,它只是防线之一。

# 5. 版本兼容问题

原生序列化还存在长期兼容问题:

  • 类名变化会影响反序列化。
  • 包名变化会影响反序列化。
  • 字段类型变化可能不兼容。
  • serialVersionUID 不一致会失败。
  • 对象图结构复杂时演进困难。

这使它不适合作为长期存储格式或跨服务协议。

# 6. 替代方案

# 6.1 JSON

优点:

  • 可读性好。
  • 调试方便。
  • 生态成熟。
  • 适合 HTTP API 和配置文件。

缺点:

  • 体积较大。
  • 性能通常不如二进制协议。
  • Schema 约束较弱。

# 6.2 Protocol Buffers

优点:

  • 跨语言。
  • 性能好。
  • 体积小。
  • Schema 清晰。
  • 适合 RPC 和服务间通信。

缺点:

  • 可读性不如 JSON。
  • 需要维护 .proto 文件。

# 6.3 Avro

适合大数据和消息系统,Schema 演进能力较好。

# 6.4 Kryo

性能较好,常见于一些 Java 生态内部序列化场景,但跨语言和长期兼容要谨慎评估。

# 7. 选型建议

  • 对外 API:JSON。
  • 内部高性能 RPC:Protocol Buffers。
  • 大数据链路:Avro、Parquet 等生态格式。
  • Java 本地临时缓存:可评估 Kryo,但要控制类型和版本。
  • 不可信输入:不要使用 Java 原生反序列化。

# 专家实践清单

场景 推荐方案 原因
外部 API JSON 可读、生态好
高性能 RPC Protobuf / Thrift Schema 明确、跨语言
大数据存储 Avro / Parquet 生态成熟、可演进
Java 本地缓存 谨慎评估 Kryo 性能好但版本要控
不可信输入 禁止原生反序列化 安全风险高

安全边界模型:

外部字节
  │ 不可信
  ▼
类型过滤 / 大小限制 / 深度限制
  │
  ▼
反序列化
  │
  ▼
业务对象

# Tips 快问快答

Q:为什么 Java 原生序列化安全风险高? A:反序列化会创建对象并触发对象链逻辑,可能被恶意构造利用。

Q:什么数据绝不能直接 readObject? A:来自用户、网络、消息队列、文件上传等不可信来源的数据。

Q:JEP 290 解决什么问题? A:提供对象输入过滤能力,可限制类型、深度、引用数和字节数。

Q:序列化格式选型看什么? A:跨语言、性能、体积、可读性、Schema 演进和安全性。

Q:JSON 的优势是什么? A:可读性和调试体验好,Web 生态成熟。

Q:Protobuf 的优势是什么? A:体积小、性能好、Schema 明确、跨语言能力强。

Q:为什么序列化要考虑版本演进? A:字段新增、删除、重命名都会影响新旧数据兼容。

Q:看到 ObjectInputStream 应该警惕什么? A:数据来源、类型白名单、依赖 gadget、对象大小和异常处理。

# 8. 总结

Java 原生序列化适合学习对象到字节的基本概念,但不适合作为现代分布式系统的默认协议。资深工程师在看到 ObjectInputStream.readObject() 处理外部输入时,应立即关注安全边界、类型过滤、依赖风险和替代方案。

上次更新: 2026/06/25, 14:19:18
字符集与乱码
try-with-resources资源管理

← 字符集与乱码 try-with-resources资源管理→

Copyright © 2023-2026 Wray | 鄂ICP备2024050235号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式