java垃圾收集安全地擦除垃圾数据?

这是一个内存数据安全问题。
java垃圾收集是否安全地清除了垃圾数据?

显然在一大块数据被垃圾收集后,我再也无法检索它了,但是黑客还可以通过内存转储来检索数据吗?

正如此处已经提到的其他用户一样,JVM在垃圾收集后不会安全地清理内存,因为它会严重影响性能。 这就是为什么许多程序(尤其是安全库)使用可变结构而不是不可变(char数组而不是字符串等),并在不再需要时自行清理数据。

不幸的是,即使这样的方法并不总是有效。 我们来看看这个场景:

  1. 您使用密码创建一个char数组。
  2. JVM执行垃圾收集并将您的char数组移动到内存中的另一个位置,使之前占用的内存保持不变,只需将其标记为空闲块即可。 所以,我们现在有一个密码的“脏副本”。
  3. 您已经完成了密码的使用,并明确地将您的char数组中的所有字符归零,认为现在一切都安全了。
  4. 攻击者转储内存,并在第2步之前第一次在内存中找到您的密码。

我只能想到这个问题的一种可能解决方案:

  1. 使用G1垃圾收集器。
  2. 使敏感数据成为单个块(原始值数组),其大小足以占用区域大小的一半以上(由G1使用)(默认情况下,此大小取决于最大堆大小,但您也可以手动指定它) )。 这将迫使收集器将您的数据视为所谓的“巨大对象”。 G1 GC不会在内存中移动这些对象。
  3. 在这种情况下,当您手动擦除块中的某些数据时,可以确保堆中某处不存在相同数据的其他“脏副本”。

另一种解决方案是使用您可以根据需要手动处理的堆外数据,但这不是纯Java。

这取决于JVM实现以及其中可能的选项,但我认为它不会清除数据。 垃圾收集只需跟踪哪些区域可用。 将所有数据设置为0或其他内容是很多不必要的写入。 出于这个原因,您经常会看到API使用char数组代替字符串而不是字符串。

具体来说,Oracle JVM不会清空空间,它只会在Eden和Survivor空间之间复制数据,不再使用的对象只会留在那里作为最终会被覆盖的垃圾。 类似的事情发生在OldGen中,有些地方被标记为已使用,当对象符合垃圾收集条件时,它占用的地方被标记为未使用。 如果有足够的应用时间,它也将被覆盖。