写点什么

Java 序列化的状态

  • 2018-09-10
  • 本文字数:6034 字

    阅读完需:约 20 分钟

关键要点

  • Java 序列化在很多库中引入了安全漏洞。
  • 对序列化进行模块化处于开放讨论状态。
  • 如果序列化能够成为模块,开发人员将能够将其从攻击表面上移除。
  • 移除其他模块可以消除它们所带来的风险。
  • 插桩提供了一种编织安全控制的方法,提供现代化的防御机制。

多年来,Java 的序列化功能饱受安全漏洞 zero-day 攻击,为此赢得了“持续奉献的礼物”和“第四个不可饶恕的诅咒”的绰号。

作为回应,OpenJDK 贡献者团队讨论了一些用于限制序列化访问的方法,例如将其提取到可以被移除的jigsaw 模块中,让黑客无法攻击那些不存在的东西。

一些文章(例如“序列化必须死”)提出了这样的建议,将有助于防止某些流行软件(如VCenter 6.5)的漏洞被利用

什么是序列化?

自从 1997 年发布 JDK 1.1 以来,序列化已经存在于 Java 平台中。

它用于在套接字之间共享对象表示,或者将对象及其状态保存起来以供将来使用(反序列化)。

在 JDK 10 及更低版本中,序列化作为 java.base 包和 java.io.Serializable 方法的一部分存在于所有的系统中。

GeeksForGeeks 对序列化的工作原理进行了详细的描述。

有关更多如何使用序列化的代码示例,可以参看 Baeldung 对 Java 序列化的介绍

序列化的挑战和局限

序列化的局限主要表现在以下两个方面:

  1. 出现了新的对象传输策略,例如 JSON、XML、Apache Avro、Protocol Buffers 等。
  2. 1997 年的序列化策略无法预见现代互联网服务的构建和攻击方式。

进行序列化漏洞攻击的基本前提是找到对反序列化的数据执行特权操作的类,然后传给它们恶意的代码。为了理解完整的攻击过程,可以参看 Matthias Kaiser 在 2015 年发表的“ Exploiting Deserialization Vulnerabilities in Java ”一文,其中幻灯片第 14 页开始提供了相关示例。

其他大部分与序列号有关的安全研究都是基于Chris Frohoff、Gabriel Lawrence 和Alvaro Munoz 的工作成果。

序列化在哪里?如何知道我的应用程序是否用到了序列化?

要移除序列化,需要从 java.io 包开始,这个包是 java.base 模块的一部分。最常见的使用场景是:

使用这些方法的开发人员应考虑使用其他存储和读回数据的替代方法。Eishay Smith 发布了几个不同序列化库的性能指标。在评估性能时,需要在基准度量指标中包含安全方面的考虑。默认的Java 序列化“更快”一些,但漏洞也会以同样的速度找上门来。

我们该如何降低序列化缺陷的影响?

项目Amber 包含了一个关于将序列化API 隔离出来的讨论。我们的想法是将序列化从java.base 移动到单独的模块,这样应用程序就可以完全移除它。在确定 JDK 11 功能集时并没有针对该提议得出任何结果,但可能会在未来的 Java 版本中继续进行讨论。

通过运行时保护来减少序列化暴露

一个可以监控风险并自动化可重复安全专业知识的系统对于很多企业来说都是很有用的。Java 应用程序可以将 JVMTI 工具嵌入到安全监控系统中,通过插桩的方式将传感器植入到应用程序中。Contrast Security 是这个领域的一个免费产品,它是 JavaOne 大会的 Duke's Choice 大奖得主。与其他软件项目(如 MySQL 或 GraalVM)类似, Contrast Security 的社区版对开发人员是免费的。

将运行时插桩应用在 Java 安全性上的好处是它不需要修改代码,并且可以直接集成到 JRE 中。

它有点类似于面向切面编程,将非侵入式字节码嵌入到源端(远程数据进入应用程序的入口)、接收端(以不安全的方式使用数据)和转移(安全跟踪需要从一个对象移动到另一个对象)。

通过集成每个“接收端”(如 ObjectInputStream),运行时保护机制可以添加额外的功能。在从 JDK 9 移植反序列化过滤器之前,这个功能对序列化和其他攻击的类型(如 SQL 注入)来说至关重要。

集成这个运行时保护机制只需要修改启动标志,将 javaagent 添加到启动选项中。例如,在 Tomcat 中,可以在 bin/setenv.sh 中添加这个标志:

CATALINA_OPTS=-javaagent:/Users/ecostlow/Downloads/Contrast/contrast.jar

启动后,Tomcat 将会初始化运行时保护机制,并将其注入到应用程序中。关注点的分离让应用程序可以专注在业务逻辑上,而安全分析器可以在正确的位置处理安全性。

其他有用的安全技术

在进行维护时,可以不需要手动列出一长串东西,而是使用像 OWASP Dependency-Check 这样的系统,它可以识别出已知安全漏洞的依赖关系,并提示进行升级。也可以考虑通过像 DependABot 这样的系统进行库的自动更新。

虽然用意很好,但默认的 Oracle 序列化过滤器存在与 SecurityManager 和相关沙箱漏洞相同的设计缺陷。因为需要混淆角色权限并要求提前了解不可知的事物,限制了这个功能的大规模采用:系统管理员不知道代码的内容,所以无法列出类文件,而开发人员不了解环境,甚至 DevOps 团队通常也不知道系统其他部分(如应用程序服务器)的需求。

移除未使用模块的安全隐患

Java 9 的模块化 JDK 能够创建自定义运行时镜像,移除不必要的模块,可以使用名为jlink 的工具将其移除。这种方法的好处是黑客无法攻击那些不存在的东西。

从提出模块化序列化到应用程序能够实际使用以及使用其他序列化的新功能需要一段时间,但正如一句谚语所说:“种树的最佳时间是二十年前,其次是现在”。

剥离 Java 的原生序列化功能还应该为大多数应用程序和微服务提供更好的互操作性。通过使用标准格式(如 JSON 或 XML),开发人员可以更轻松地在使用不同语言开发的服务之间进行通信——与 Java 7 的二进制 blob 相比,python 微服务通常具有更好的读取 JSON 文档的集成能力。不过,虽然 JSON 格式简化了对象共享,针对 Java 和.NET 解析器的“ Friday the 13th JSON attacks ”证明了银弹是不存在的(白皮书)。

在进行剥离之前,序列化让然保留在 java.base 中。这些技术可以降低与其他模块相关的风险,在序列化被模块化之后,仍然可以使用这些技术。

为 Apache Tomcat 8.5.31 模块化 JDK 10 的示例

在这个示例中,我们将使用模块化的 JRE 来运行 Apache Tomcat,并移除任何不需要的 JDK 模块。我们将得到一个自定义的 JRE,它具有更小的攻击表面,仍然能够用于运行应用程序。

确定需要用到哪些模块

第一步是检查应用程序实际使用的模块。OpenJDK 工具 jdeps 可以对 JAR 文件的字节码执行扫描,并列出这些模块。像大多数用户一样,对于那些不是自己编写的代码,我们根本就不知道它们需要哪些依赖项或模块。因此,我使用扫描器来检测并生成报告。

列出单个 JAR 文件所需模块的命令是:

jdeps -s JarFile.jar

它将列出模块信息:

tomcat-coyote.jar -> java.base
tomcat-coyote.jar -> java.management
tomcat-coyote.jar -> not found

最后,每个模块(右边的部分)都应该被加入到一个模块文件中,成为应用程序的基本模块。这个文件叫作 module-info.java,文件名带有连字符,表示不遵循标准的 Java 约定,需要进行特殊处理。

下面的命令组合将所有模块列在一个可用的文件中,在 Tomcat 根目录运行这组命令:

find . -name *.jar ! -path "./webapps/*" ! -path "./temp/*" -exec jdeps -s {} \; | sed -En "s/.* -\> (.*)/  requires \1;/p" | sort | uniq | grep -v "not found" | xargs -0 printf "module com.infoq.jdk.TomcatModuleExample{\n%s}\n"

这组命令的输出将被写入 lib/module-info.java 文件,如下所示:

module com.infoq.jdk.TomcatModuleExample{
  requires java.base;
  requires java.compiler;
  requires java.desktop;
  requires java.instrument;
  requires java.logging;
  requires java.management;
  requires java.naming;
  requires java.security.jgss;
  requires java.sql;
  requires java.xml.ws.annotation;
  requires java.xml.ws;
  requires java.xml;
}

这个列表比整个 Java 模块列表要短得多。

下一步是将这个文件放入 JAR 中:

javac lib/module-info.java
jar -cf lib/Tomcat.jar lib/module-info.class

最后,为应用程序创建一个 JRE:

jlink --module-path lib:$JAVA_HOME/jmods --add-modules ThanksInfoQ_Costlow --output dist

这个命令的输出是一个运行时,包含了运行应用程序所需的恰到好处的模块,没有任何性能开销,也没有了未使用模块中可能存在的安全风险。

与基础 JDK 10 相比,只用了 98 个核心模块中的 19 个。

java --list-modules

com.infoq.jdk.TomcatModuleExample
java.activation@10.0.1
java.base@10.0.1
java.compiler@10.0.1
java.datatransfer@10.0.1
java.desktop@10.0.1
java.instrument@10.0.1
java.logging@10.0.1
java.management@10.0.1
java.naming@10.0.1
java.prefs@10.0.1
java.security.jgss@10.0.1
java.security.sasl@10.0.1
java.sql@10.0.1
java.xml@10.0.1
java.xml.bind@10.0.1
java.xml.ws@10.0.1
java.xml.ws.annotation@10.0.1
jdk.httpserver@10.0.1
jdk.unsupported@10.0.1

运行这个命令后,就可以使用 dist 文件夹中的运行时来运行应用程序。

看看这个列表:部署插件(applet)消失了,JDBC(SQL)消失了,JavaFX 也不见了,很多其他模块也消失了。从性能角度来看,这些模块不再产生任何影响。从安全角度来看,黑客无法攻击那些不存在的东西。保留应用程序所需的模块非常重要,因为如果缺少这些模块,应用程序也无法正常运行。

关于作者

Erik Costlow 是甲骨文的 Java 8 和 9 产品经理,专注于安全性和性能。他的安全专业知识涉及威胁建模、代码分析和安全传感器增强。在进入技术领域之前,Erik 是一位马戏团演员,可以在三轮垂直独轮车上玩火。

查看英文原文 The State of Java Serialization

2018-09-10 18:222682
用户头像

发布了 731 篇内容, 共 448.8 次阅读, 收获喜欢 2002 次。

关注

评论

发布
暂无评论
发现更多内容

欢迎 Apache ShardingSphere 社区海外新晋 Committer!

SphereEx

开源社区 ShardingSphere SphereEx Committer

第四范式x英特尔“AI应用与异构内存编程挑战赛”圆满收官

第四范式开发者社区

WeTest.net全球能力开放:锻造高品质产品,构建全球竞争力

WeTest

Java 处理表格,真的很爽!

程序员鱼皮

Java

分析师机构发布中国低代码平台现状分析报告,华为云AppCube为数字化转型加码

华为云开发者联盟

低代码 数字化 华为云 低代码平台 AppCube

如果你正在准备面试TCP,看这一篇就够了

热爱java的分享家

Java 架构 程序人生 编程语言 经验分享

图文并茂!你管这破玩意儿叫TCP?

热爱java的分享家

Java TCP 程序人生 编程语言 经验分享

这一次,飞书改变「飞书」

ToB行业头条

嵌入式系统软件开发:你需要知道的一切

龙智—DevSecOps解决方案

嵌入式系统 嵌入式系统软件开发

金融级数据库新坐标:腾讯云TDSQL发布全自研新敏态引擎

腾讯云数据库

数据库 tdsql

混沌工程:分布式系统稳定性的“疫苗”

中原银行

微服务 云原生 混沌工程

TDSQL | 云时代,我们到底需要怎样的数据库?

腾讯云数据库

数据库 tdsql

前端避坑指南丨辛辛苦苦开发的APP竟然被判定为简单网页打包?

YonBuilder低代码开发平台

Go语言学习查缺补漏ing Day4

Regan Yue

Go 语言 11月日更

保持清洁的Git提交记录,三招就够了

Geek_1df311

Java 开源 架构 git 学习

Flux 源码之reactor 核心原理及概述

漫游指南

reactor Flux

业务流程建模,你真的做对了吗

明道云

TDengine助力顺丰科技大数据监控改造

TDengine

tdengine 时序数据库

TDSQL | 数据异常的本质和价值详解

腾讯云数据库

数据库 tdsql

使用ABAP代码返回S/4HANA Material上维护的Attachment明细

汪子熙

SAP S/4HANA 11月日更 Material

如何使用SAP CRM Marketing Survey创建一个市场问卷调查

汪子熙

SAP abap 11月日更 Survey

秀出新天际的SpringBoot笔记,让开发像搭积木一样简单

热爱java的分享家

Java 架构 程序人生 编程语言 经验分享

Docker心经

卫先生

Python 编译器 编译器远程连接docker docker常用命令 docker总结

什么是色彩心理学?

坚果

心理学 11月日更

恒源云(GPUSHARE)_教你如何团队合作搞算力!

恒源云

人工智能 深度学习 云算力

供应链安全隐患迫在眉睫,2021年全球APT攻击暗藏何种趋势?

科技热闻

云小课 | SA基线检查---给云服务的一次全面“体检”

华为云开发者联盟

态势感知 华为云 基线检查 上云合规 全面体检

大咖说·未来组织的底层逻辑

大咖说

云计算

Alibaba 新产 SpringCloud Aliababa(全彩第四版)开源

Geek_1df311

Java 编程 架构 微服务

打造数字化软件工厂 —— 一站式 DevOps 平台全景解读

CODING DevOps

DevOps 研发管理 CODING

TDSQL | HTAP系统的问题与主义之争

腾讯云数据库

数据库 tdsql

Java序列化的状态_Java_Erik Costlow_InfoQ精选文章