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

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将会按照顺序发挥作用:

Bootstrap ClassLoader:JVM本身的一部分,因此在每个JVM中,它的实现都是特有的。这个ClassLoader没有父ClassLoader,它用于加载java.lang包下的核心类。

Extension ClassLoader:负责加载扩展库中的类,在每个Java安装环境下可能会有所差别。Extension ClassLoader将会加载java.ext.dirs变量所指定路径下的所有内容。

Application ClassLoader:负责加载应用程序的主类以及所有位于应用类路径下的类。

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并没有进行检查,这意味着攻击者可以按照上文所述的方法进行类的仿造。

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

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/383746d080adaf9ebd3cdd3dcbff0f70.html