多年来,Java的序列化功能饱受安全漏洞和zero-day攻击,为此赢得了“持续奉献的礼物”和“第四个不可饶恕的诅咒”的绰号。
作为回应,OpenJDK贡献者团队讨论了一些用于限制序列化访问的方法,例如将其提取到可以被移除的jigsaw模块中,让黑客无法攻击那些不存在的东西。
一些文章(例如“序列化必须死”)提出了这样的建议,将有助于防止某些流行软件(如VCenter 6.5)的漏洞被利用。
什么是序列化?
自从1997年发布JDK 1.1以来,序列化已经存在于Java平台中。
它用于在套接字之间共享对象表示,或者将对象及其状态保存起来以供将来使用(反序列化)。
在JDK 10及更低版本中,序列化作为java.base包和java.io.Serializable方法的一部分存在于所有的系统中。
GeeksForGeeks对序列化的工作原理进行了详细的描述。
有关更多如何使用序列化的代码示例,可以参看Baeldung对Java序列化的介绍。
序列化的挑战和局限
序列化的局限主要表现在以下两个方面:
出现了新的对象传输策略,例如JSON、XML、Apache Avro、Protocol Buffers等。
1997年的序列化策略无法预见现代互联网服务的构建和攻击方式。
进行序列化漏洞攻击的基本前提是找到对反序列化的数据执行特权操作的类,然后传给它们恶意的代码。为了理解完整的攻击过程,可以参看Matthias Kaiser在2015年发表的“Exploiting Deserialization Vulnerabilities in Java”一文,其中幻灯片第14页开始提供了相关示例。
其他大部分与序列号有关的安全研究都是基于Chris Frohoff、Gabriel Lawrence和Alvaro Munoz的工作成果。
序列化在哪里?如何知道我的应用程序是否用到了序列化?
要移除序列化,需要从java.io包开始,这个包是java.base模块的一部分。最常见的使用场景是:
实现Serializable接口和(可选)serialversionuid长整型字段。
使用ObjectInputStream或ObjectOutputStream。
使用严重依赖序列化的库,例如:Xstream、Kryo、BlazeDS和大多数应用程序服务器。
使用这些方法的开发人员应考虑使用其他存储和读回数据的替代方法。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将会初始化运行时保护机制,并将其注入到应用程序中。关注点的分离让应用程序可以专注在业务逻辑上,而安全分析器可以在正确的位置处理安全性。
大型站长资讯类网站! https://www.0792zz.cn