Java是否存在缓冲区溢出?

106

Java是否存在缓冲区溢出?如果有,你能举例说明吗?


2
一些库函数(实现在本地代码中)已知存在漏洞。特别是在Java 5领域,许多2D、声音或颜色配置文件的漏洞已经被发现。 - eckes
10个回答

121

由于 Java 字符串基于 char 数组,并且 Java 自动检查数组边界,因此缓冲区溢出只可能发生在以下不寻常的情况下:

  1. 通过 JNI 调用本地代码
  2. 在 JVM 本身中(通常是用 C++ 编写的)
  3. 解释器或 JIT 编译器不能正确工作(Java 字节码要求边界检查)

30

像Java和C#这样的托管语言没有这些问题,但实际运行代码的具体虚拟机(JVM/CLR等)可能会遇到这些问题。


5
在不安全的上下文中使用C#可能会发生缓冲区溢出。作为一种编程语言,Java完全禁止这种情况的发生(你必须通过JNI更改语言才能获得未管理指针访问权限)。 - ShuggyCoUk
1
好的观点。使用不安全的C#,显然你不再处于舒适的托管世界中。 - Brian Rasmussen
1
没错,即使你自己不写任何不安全的代码或进行任何交互操作,你可能会使用一个包含不安全代码的库。因此,这是需要注意的事情。 - BobbyShaftoe

15

就所有目的而言,不会。

Java具有数组边界检查,它将检查数据是否无法从分配的数组区域外访问。当尝试访问超出数组大小的区域时,将抛出ArrayOutOfBounds异常。

如果存在缓冲区溢出,则可能是Java虚拟机中的错误,据我所知,这不是Java语言规范或Java虚拟机规范中编写的预期行为。


10

是和不是。不是因为它是一种托管内存模型,所以你实际上无法创建错误地打开自己的缓冲区溢出漏洞。但是,在JVM和JDK中可能存在缓冲区溢出漏洞。请参阅Secunia公告:

http://secunia.com/advisories/25295

或者查看这些旧的建议,针对几个以前的JDK和JRE漏洞:

  • Java运行时环境(JRE)中的整数和缓冲区溢出漏洞,使用“unpack200” JAR解包实用程序可能导致特权升级 https://download.oracle.com/sunalerts/1020225.1.html

    在使用“unpack200” JAR解包实用程序解包小程序和Java Web Start应用程序时,Java运行时环境(JRE)中的整数和缓冲区溢出漏洞可能允许不受信任的小程序或应用程序提升权限。例如,不受信任的小程序可能授予自己读写本地文件或执行用户正在运行不受信任的小程序的可访问的本地应用程序的权限。

    Sun感谢“regenrecht”与iDefense VCP(http://labs.idefense.com/vcp/)和Google的Chris Evans将这些问题带到我们的注意下。

  • 已在Sun Java开发套件(JDK)和Java运行时环境(JRE)中识别出多个漏洞。https://security.gentoo.org/glsa/200705-23

    藤田安全团队报告了涉及“系统类的错误使用”的未指定漏洞。此外,Google安全团队的Chris Evans报告了一个整数溢出,导致ICC解析器与JPG或BMP文件一起使用时出现缓冲区溢出,并且在处理某些BMP文件时调用了不正确的open()函数。


9

严格意义上的缓冲区溢出指的是覆盖堆栈或堆本身,这将需要以下两个条件之一:

  1. 框架中存在漏洞(过去曾经存在过,未来也可能再次存在)
  2. 使用JNI(基本上不再使用托管代码)

如果您的代码使用缓冲区并且您的代码负责正确解析它但未能这样做,则可能会发生缓冲区溢出。 例如,您可能编写了一个XML解析器,而某人可能会向您提供一个格式不正确(或合法但不常见)的请求,由于您解析器的设计覆盖了先前验证的数据,并且使用了一些有效载荷,导致应用程序表现不佳。

后一种形式不太可能发生,但是广泛分发的编写不良的SQL字符串清理函数如果存在此类问题,将成为一个受欢迎的目标。


4

Java(以及.Net)虚拟机可以捕获试图写入保留内存之外的代码。如果应用程序没有正确处理这种情况,仍然可能导致安全问题。如果恶意用户可以通过输入无效输入触发异常,例如他们可以进行拒绝服务攻击。


3

正如已经指出的那样,Java作为一种语言,在所有内存访问上都有边界检查,如果出现错误,则是JVM的问题而不是程序的问题。然而,应该注意的是,这与Java中的内存泄漏类似;虽然无法破坏堆栈,但在错误的位置引发的ArrayOutOfBoundsException(数组越界异常),如果没有正确处理,仍可能导致系统崩溃。


3

如果您使用Java Native Interface(JNI)调用外部代码,并且外部代码存在可利用的问题,则可能导致Java程序中的缓冲区溢出。这种情况相对较少见,因为大多数应用程序在可能的情况下避免使用JNI。


3

有时候方法会因为整数溢出而将数据写入到本不应该被写入的有效数组条目中。

例如,以下代码并不能充分检查数组边界:

/* !! WRONG !! */ 0 <= off && 0 <= len && off+len <= buff.length /* !! WRONG !! */

据我所知,StringBuffer曾经有过这样的一个bug,但它并没有什么有趣的用途。

检查边界需要什么条件? - Broam
1
@Broam: 我认为应该是 0 <= off && 0 <= len && off <= buff.length-len。但不要引用我。虽然看起来一样,但原始的 off+len 可能会变成负数,因此显然小于数组长度,这里没有可能溢出。请确保没有维护程序员将其整理成明显的形式。我觉得整数溢出非常令人困惑。必须花一些时间思考,然后有一种烦人的怀疑感,觉得自己搞错了。但当然,还应该有另一个审阅者和原始程序员 - 当然,这样就不可能出现错误!(并不是) - Tom Hawtin - tackline
我不得不盯着这个看了一会儿,但你是对的。在C中,off + len可能会溢出和包装...但在Java中,除非我弄错了,否则在发生这种情况之前,你会得到一个溢出异常,对吗? - Broam
1
没有。整数算术静默地环绕。C#有一种“模式”,在溢出时会抛出异常,但我认为它并没有被广泛使用(如果你想使用它,你可能已经想到了正确的做法)。 - Tom Hawtin - tackline

1
JAVA的一个关键特性是安全性。使用解释型语言编写的程序不容易受到缓冲区溢出攻击,但你始终可以在解释器本身中引起缓冲区溢出,尽管这很困难。同样,Python也是一种解释型语言,因此不会受到缓冲区溢出的影响。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接