写点什么

Java 反射库中的安全漏洞在 30 个月后终于修复了

  • 2016-05-16
  • 本文字数:2894 字

    阅读完需:约 9 分钟

2013 年 7 月,安全组织 Security Explorations 发现了 Java 7u25 中的一个安全漏洞,通过这个漏洞攻击者可以完全摆脱 Java 沙箱。Oracle 在更新的 7u40 中包含了一个补丁,但是据 Security Explorations 在今年早些时候声称,这个补丁仅仅在理念上对其进行了修正,对代码稍加修改之后,依然可以利用这个漏洞。另外,随后的研究表明这个漏洞甚至比最初报道的更加严重。在这个问题公开之后,Oracle 发布了一个补丁,作为 8u77 的一部分。

这个漏洞可以在新的反射库中找到,该库从 Java 7 以后均可以使用,更具体来讲,是在使用新的 MethodHandle 类动态访问和调用方法的时候。它与不同 ClassLoader 加载类的方式有关。要理解这个问题,需要一些基本的知识,这些知识涉及到 Java ClassLoader 的工作方式, 因为类加载是在 Java 中大家了解最少的领域之一,所以在阐述这个问题本身之前,我们会首先概述一下这个理念。

Java ClassLoader

Java 能够在运行时从各种来源动态加载代码。这种功能是通过一系列名为 ClassLoader 的特殊类来实现的。标准的 Java 实现会提供多个 ClassLoader 来加载类,它们能够从文件系统、URL 或压缩文件等位置加载类,不过 Java 也为开发人员提供了创建自定义 ClassLoader 的能力,以应对个性化的需求。与 ClassLoader 交互的常见方式是调用其 loadClass(String) 方法,这个方法会接受类的名称,如果能够找到的话,就会返回相关的 Class 对象,如果找不到的话,就会抛出 ClassNotFoundException 异常。在 Java 应用中的每个类都是通过某个 ClassLoader 按照这种方式加载的。

通过设置父 ClassLoader,这些不同的 ClassLoader 能够互相连接起来,形成一个层级的结构。如果没有设置父 ClassLoader 的话,那么父 ClassLoader 默认将会设置为加载该 ClassLoader 的那个类加载器(ClassLoader 本身也是类,因此也需要通过某个 ClassLoader 来进行加载)。如果提供了父 ClassLoader 的话,那么 ClassLoader 的默认行为就是将加载所请求类的任务委托给它的父加载器,只有父加载器(或祖父加载器)无法加载这个类的时候,这个 ClassLoader 本身才会试图加载所请求的类。但是,自定义加载器的创建者并非强制性要求遵循这种默认行为,他们完全可以选择实现不同的行为。

当 Java 应用启动的时候,如下的 ClassLoader 将会按照顺序发挥作用:

  1. Bootstrap ClassLoader:JVM 本身的一部分,因此在每个 JVM 中,它的实现都是特有的。这个 ClassLoader 没有父 ClassLoader,它用于加载 java.lang 包下的核心类。
  2. Extension ClassLoader:负责加载扩展库中的类,在每个 Java 安装环境下可能会有所差别。Extension ClassLoader 将会加载 java.ext.dirs 变量所指定路径下的所有内容。
  3. Application ClassLoader:负责加载应用程序的主类以及所有位于应用类路径下的类。
  4. Custom ClassLoader:应用程序中使用的所有其他的 ClassLoader。它是可选的,根据应用的情况不同,它可能并不存在。

在运行时,使用自定义的 ClassLoader 动态加载类为很多的应用创造了可能性,否则的话,有些功能可能是无法实现的,不过,遗憾的是,它也造成了很多的安全问题,尤其是在类仿造(class impersonation)方面。理论上,开发人员可以创建一个自定义的 ClassLoader,让它来加载原始类 java.lang.Object 的一个模拟实现,并在应用程序中使用这个自定义的对象。这可能会在两个方面引发安全问题:这个自定义的对象能够访问 java.lang 包下所有包范围内可见的类内容;其次,这个自定义的 Object 会被 JVM 作为标准的 Object 对象,因此会将其作为由 Java 实现的可信任的类。

为了保护 Java 以应对这些安全问题,Java 类要通过三个属性来进行识别:类名、包以及 ClassLoader 的引用。如果两个不同的类具有相同的类名和包名,但是由不同的 ClassLoader 所加载的话,Java 会认为它们是不相等的,在它们两者之间进行赋值的话,将会导致 ClassCastException 异常。这样的话,就能保护环境免受类仿造的攻击。

部分修复以及由此导致的漏洞

Security Explorations 最早报告了这个漏洞,并将其归类为 CVE-2013-5838 ,这个漏洞可以描述为,当通过 Method Handle 调用方法时,对于被调用方法的那个类,它的 ClassLoader 并没有进行检查,这意味着攻击者可以按照上文所述的方法进行类的仿造。

展现原始漏洞的代码样例,目标类的 ClassLoader 并没有进行检查;来源: Security Explorations

Oracle 在 2013 年 9 月提供了一个修正,作为 Java 7u40 的一部分,包含了类可见性的检查,它会对比预期类型和传入类型的 ClassLoader,对比方式如下:

  • 如果两个 ClassLoader 相同的话,那么按照定义这两个类型是完全兼容的;
  • 如果其中一个 ClassLoader 是另一个 ClassLoader 的父加载器,那么它认为这两个类是通过正常的 ClassLoader 层级结构加载的,因此将其视为相等是安全的。

在第二项检查中,Security Explorations 发现 exploit 稍加修改就可能继续有效。首先,用于仿造类的自定义 ClassLoader 将目标 ClassLoader 设置为它的父类加载器,这可以通过 API 以参数的方式进行设置:

复制代码
URLClassLoader lookup_CL = URLClassLoader.newInstance(urlArray, member_CL);

通过该机制将自定义的 ClassLoader 作为等级结构的一部分,来源: Security Explorations

然后,鉴于 ClassLoader 的默认行为是将加载类的任务委托给它的父加载器,攻击者就需要确保父 ClassLoader 无法加载到这个类,这样他们自定义的 ClassLoader 就能发挥作用了。借助 Java 以网络方法加载类的过程,这种攻击模式得到了印证:如果这个类通过 URL 位置的方式来进行定义的话,父 ClassLoader 将会试图连接相关的服务器并获取这个类的代码,此时,预先构建好的 HTTP 服务器可以返回 404 NOT FOUND 错误,让父 ClassLoader 加载这个类出现失败,因此就会将控制权转移给自定义的 ClassLoader。

通过自定义的 HTTP 服务器,强制父 ClassLoader 加载类失败之后的代码流,来源: Security Explorations

当这个缺陷 2016 年 3 月重新爆出时,当时最新的可用版本是 8u74,这个版本被证明是有漏洞的,Oracle 在 8u77 中为其提供了修正。但是,在 8u77 的发布说明中,这个漏洞依然描述为“会影响桌面设备上,Web 浏览器中所运行的 JavaSE[并且] 不会影响到 Java 部署环境,比如典型的服务器或独立部署的桌面应用”,但是事实证明,它还是会影响服务器配置以及 Google App Engine 的 Java 环境。

修正:2016 年 4 月 29 日

本文错误地认为这个漏洞在 8u77、8u91 和 8u92 版本中依然存在,实际上,在 8u77 中它已经得到了修正。在 8u77 的发布说明中将其描述为对 CVE-2016-0636 的修正,具体描述是这样的“未指明的漏洞 […] 借助 Hotspot 子组件中未知的感染内容”并且没有包含对本文中所提及的 CVE-2013-5838 的明确引用。但是,Security Explorations 指出 CVE-2016-0636 是针对 Issue 69 的一个 CVE 编号,而 Issue 69 是他们自己代指最初 CVE-2013-5838 的一种方式。(在本文英文原文的评论区,讨论了该问题解决的相关过程,感兴趣的读者可以访问原文查看。——译者注)

查看英文原文 Vulnerability in Java Reflection Library Fixed after 30 Months

2016-05-16 19:004098

评论

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

字节一面:HTTPS 一定安全可靠吗?

程序员小毕

Java 程序员 面试 https 校招

修筑产学研用一体化的通衢,从一场比赛背后瞭望苏州园区人才培养新范式

脑极体

SAP ABAP 和 Java 里的弱引用(WeakReference)和软引用(SoftReference)

汪子熙

Java 引用 SAP abap 8月月更

【8.12-8.19】写作社区精彩技术博文回顾

InfoQ写作社区官方

优质创作周报

7 天能找到 Go 工作吗?学学 Go 数组和指针试试

梦想橡皮擦

Python 爬虫 8月月更

开源一夏 | 在 STM32L051 上使用 RT-Thread (四、无线温湿度传感器 之 串口通讯)

矜辰所致

开源 RT-Thread 8月月更 STM32L051

九章云极DataCanvas公司与中国信通院完成可信AI基础软件战略合作

九章云极DataCanvas

人工智能 数据智能 数智化 可信AI

如何避免数据湖变成数据沼泽

Kyligence

数据湖 数据管理 智能多维数据库

数据中台逼近炒作顶峰之际,Gartner给想建数据中台的一些建议

雨果

数据中台 Gartner

Meta项目功能测试 | 开启PrestoDB和Aria扫描优化

Alluxio

hive presto Alluxio 大数据 开源 8月月更

前半个月的行动中,整个圈子都在疯传的“内网King”到底是个啥?

青藤云安全

网络安全 主机安全 攻防演练

Web3.0 DAPP项目智能合约系统开发技术详情

开发微hkkf5566

云图说丨初识可信分布式身份服务

华为云开发者联盟

云计算 安全 后端

5分钟,带你看完24岁60W年薪架构师的简历,上面竟然写着精通JVM

收到请回复

Java JVM java面试 简历模板 金九银十

基于RPC接口的业务侧流量回放

转转技术团队

测试工具 流量回放 测试方案

打了15天,如何做到在容器权限上不失一分?

青藤云安全

容器安全 攻防演练

马拉车算法 (最长回文串 例题 密码截获)

Five

算法 8月月更

一文搞懂EMAS Serverless小程序开发|电子书免费下载

hum建应用专家

Serverless emas

四个层次管好设备,为生产保驾护航

PreMaint

预测性维护 设备管理 设备预测性维护

前端监控系列3 | 如何衡量一个站点的性能好坏

字节跳动终端技术

字节跳动 前端 性能监控 火山引擎 站点性能

一文带你认知定时消息发布RocketMQ

华为云开发者联盟

云计算 后端

优雅,永不过时!SpringBoot中这样编写Controller层代码,那叫一个完美

Java永远的神

Java 程序员 面试 程序人生 springboot

龙蜥开发者说:我眼里的龙蜥社区:一个包容的大家庭 | 第 10 期

OpenAnolis小助手

Linux 开源 操作系统 龙蜥开发者说 参与贡献

什么是企业知识库?有什么作用?如何搭建?@附源码

金陵老街

Java、 企业数字化转型 spring-boot

数字知识库-知识图谱管理系统

金陵老街

Java 数字化 知识图谱 企事业系统

高效完成需求计划的四个关键 | 敏捷开发

LigaAI

Scrum 敏捷开发 Sprint LigaAI spring event

如何在企业数字化团队内部实现数据分析建模成果的结构化整合沉淀

ModelWhale

工作流 数字化转型 数字化 案例分享 提高效率

开源一夏 | 在 STM32L051 上使用 RT-Thread (三、无线温湿度传感器 之 I2C通讯)

矜辰所致

开源 RT-Thread 8月月更 STM32L051

ABAP 一组关键字 IS BOUND, IS NOT INITIAL 和 IS ASSIGNED 的用法辨析

汪子熙

指针 应用 SAP abap 8月月更

Python图像处理丨基于OpenCV和像素处理的图像灰度化处理

华为云开发者联盟

Python 人工智能 图像

OpenHarmony有氧拳击之设备端开发

OpenHarmony开发者

OpenHarmony

Java反射库中的安全漏洞在30个月后终于修复了_Java_Abraham Marín Pérez_InfoQ精选文章