【发布时间】:2023-03-14 18:51:02
【问题描述】:
上下文
我最近参加了一场密码学讲座,我们讨论了关键元素在内存中的持久性。通常,C/C++ 库 Libsodium 建议清除任何包含敏感信息的缓冲区,例如机密 (ref)。我知道GuardedString 由字节数组支持,文档建议在不再使用存储的秘密后调用方法dispose,使用Arrays.fill 填充字节数组。
问题
JVM 是否保证字节数组的值在被覆盖时会消失,或者在某些条件下原始值是否会保留在内存中?例如,未使用/未引用的Strings 保存在 Java 字符串池 中,直到触发垃圾回收。是否有类似的 缓存 或其他类型的机制,例如可以破坏应该从 GuardedString 处理的秘密的字节数组? JVM规范中的任何参考?
非常感谢!
【问题讨论】:
-
例如见stackoverflow.com/a/121798/1531124。理论上,将空值写入数组应该已经足够了。
-
JVM 是否保证... 不,JVM 还没有实现那种安全内存。
-
@GhostCat 理论上,JVM 可以消除任何从不跟随读取的写入,即对之后放弃的对象进行的写入。此外,由于复制垃圾收集器,未知数量的副本可能已经在堆内存中飞来飞去。 在实践中,即使没有真正的保证,这种零填充可能已经足够了。
-
@ZenLulz 字符串池在这里无关紧要。密码字符串不会进入池中,除非您明确输入(通常不会这样做)。但无论它是否在池中,所有对象都保留在内存中,直到触发垃圾回收。即使在垃圾回收之后,它们的内容也可能会在内存中保留一段未知的时间,直到它被覆盖以重新使用该特定内存的实际新分配。
-
@GhostCat 我指的是通常尝试在您知道以后根本不会使用该数组的地方用零填充数组。在这种情况下,JVM 不太可能检测到这是对象的最后一次使用,因此写入已过时。原则上,JVM 可以消除 任何 内存访问,只要它可以确保读取被先前写入的值正确替换,就像在逃逸分析之后发生的那样。但是当然,如果密码根本没有写入内存,我们就没有问题。
标签: java cryptography jvm internals