Java垃圾回收是否安全地擦除垃圾数据?

7

这是一个有关内存数据安全的问题。
Java垃圾回收是否可以安全清除垃圾数据?

显然,在一段数据被垃圾回收后,我就不能再检索它了,但黑客是否仍然可以进行内存转储以检索数据?


相关链接:https://dev59.com/rGox5IYBdhLWcg3w74q2 - shmosel
内存安全很难做到。而且当有人侵入你的手机来扫描内存中的数据时,他们几乎可以获取你的手机中大部分的安全信息。我们应该把更多的精力放在保护存储和传输中的数据上面。 - david m lee
我担心的是HIPAA合规性问题。不确定HIPAA合规要求是否需要内存加密。 - Liwen Zhao
3个回答

6
正如其他用户在这里提到的,JVM在垃圾回收后不会安全地清除内存,因为这会严重影响性能。这就是为什么许多程序(特别是安全库)使用可变结构而不是不可变结构(例如字符数组而不是字符串等),并在不再需要时自己清理数据。
不幸的是,即使采用这种方法也并不总是有效。让我们看看以下场景:
1. 您创建了一个带密码的字符数组。 2. JVM执行垃圾回收并将您的字符数组移动到内存中的另一个位置,保留原先占用的内存,只将其标记为空闲块。因此,我们现在有了一个“脏副本”密码。 3. 您完成了与密码的工作,并明确将字符数组中的所有字符设置为零,认为现在一切都很安全。 4. 攻击者对您的内存进行转储,并在第2步之前放置密码的内存中找到了您的密码。
我只能想到一个可能的解决方案:
1. 使用G1垃圾回收器。 2. 将敏感数据制作成单个块(原始值数组),该块足够大,可以占用G1使用的区域大小的一半以上(默认情况下,此大小取决于最大堆大小,但也可以手动指定)。这将迫使收集器将您的数据视为所谓的“巨大对象”。这些对象不会被G1 GC在内存中移动。 3. 在这种情况下,当您手动擦除块中的某些数据时,您可以确信没有其他相同数据的“脏副本”存在于堆中的其他地方。
另一个解决方案是使用您可以自己处理的离堆数据,但那将不是纯Java。

在Go中,您可以使用系统调用(如mmap/virtualalloc等)直接从内核请求内存,而且是使用纯Go语言。不确定Java是否有类似的功能。 - Awn

2

这取决于JVM的实现以及其中可能存在的选项,但我认为它不会清除数据。垃圾回收只需要跟踪哪些区域可用。将所有数据设置为0或其他值是很多不必要的写操作。因此,您经常会看到API使用字符数组来存储密码,而不是字符串。


值得一提的是,字符数组只能降低攻击成功的概率,但不能完全消除攻击的可能性。 - Andrew Lygin
@AndrewLygin 对的,我也没有提到你需要自己清空数组。 数组本身并没有防止从内存转储中读取它的内容的特性。 - JimmyJames
不幸的是,这里的情况有些复杂,即使手动清除数据也不总能完全摆脱它们。请参阅我的答案以获取详细信息。 - Andrew Lygin
我并不是想暗示这是一种安全的方法,但使用字符数组的原因是为了尝试清除它。 - JimmyJames
当然,你是对的。我只是多次看到人们建议使用可变结构并手动清理它们作为绝对安全的方法。只是想明确一下,这并不是真的。 - Andrew Lygin
@AndrewLygin 绝对是一条有帮助的评论。你的回答在这个问题上有非常好的细节。 - JimmyJames

0

具体而言,Oracle JVM 不会清理空间,它只会在 Eden 和 Survivor 空间之间复制数据,不再使用的对象仍然留在那里成为垃圾,最终将被覆盖。类似的事情也会发生在 OldGen 中,一些地方被标记为已使用,当对象符合垃圾收集条件时,它所占用的位置将被标记为未使用。随着足够的应用程序时间,它也将最终被覆盖。


Oracle JVM是典型的Java虚拟机吗? 我更关注Android应用程序的数据安全。 - Liwen Zhao
@LiwenZhao Android(或者更准确地说是Dalvik/ART)不是JVM,因此您无法在其中应用任何JVM的内容。请在您的问题中添加“android”注释。Oracle是JVM的参考实现。 - Krzysztof Krasoń

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