【问题标题】:does java garbage collection securely wipe out garbage data?java垃圾收集是否安全地清除垃圾数据?
【发布时间】:2016-07-29 18:19:26
【问题描述】:

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

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

【问题讨论】:

  • 内存安全很难做到。此外,当有人闯入您的手机扫描内存以获取数据时,他们几乎可以从您的手机中获取大部分安全信息。可以更好地努力保护存储和传输中的数据。
  • 我担心的是 HIPAA 合规性。不确定 HIPAA 合规性是否需要内存加密。

标签: java garbage-collection


【解决方案1】:

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

不幸的是,即使这样的方法也并不总是奏效。让我们看一下这个场景:

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

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

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

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

【讨论】:

  • 在 Go 中,您可以使用系统调用使用纯 Go 直接从内核(mmap/virtualalloc 等)请求内存。不确定在 Java 中是否有类似的可能。
【解决方案2】:

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

【讨论】:

  • 值得一提的是,char数组只会降低攻击成功的概率,但不能保证完全消除。
  • @AndrewLygin 对。我也没有提到您需要自己清除数组。数组本身并没有阻止从内存转储中读取它的内容。
  • 不幸的是,这里的事情有点复杂,即使手动清除数据也并不总是可以完全摆脱它们。详情见我的回答。
  • 我并不是要暗示这是一种安全的方法,但使用 char 数组的原因是为了尝试清除它。
  • 当然,那你是对的。我刚刚看到很多次人们建议使用可变结构并手动清理它们作为绝对安全的方法。只是想澄清事实并非如此。
【解决方案3】:

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

【讨论】:

  • Oracle JVM 是典型的 Java VM 吗?我更关心 Android 应用数据的安全性。
  • @LiwenZhao Android(或者更确切地说是 Dalvik/ART)不是 JVM,因此您不能将任何来自 JVM 的东西应用到它。请使用android 注释您的问题。 Oracle 是 JVM,参考实现。
猜你喜欢
  • 2010-12-13
  • 2011-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-11
  • 2011-11-07
  • 1970-01-01
  • 2018-09-06
相关资源
最近更新 更多