>上下文
我最近有一个密码学讲座,我们讨论了内存中关键元素的持久性。通常,C/C++库 Libsodium 建议清除任何包含敏感信息的缓冲区,例如机密 (ref)。我知道GuardedString
由字节数组支持,文档建议调用该方法dispose
一旦不再使用存储的密钥,就会使用Arrays.fill
填充字节数组。
问题
JVM是否保证字节数组的值在被覆盖时消失,或者在某些情况下原始值可能保留在内存中?例如,未使用/未引用的String
在Java 字符串池中保存,直到触发垃圾回收。对于其他类型的缓存或机制,是否有类似的缓存或机制,例如字节数组,可能会破坏应从GuardedString
中释放的机密?JVM的规格中的任何参考?
非常感谢 !
在Java中,通常使用数组而不是String
char[]
因为这允许手动将数组中的数据归零。
但是,即使这样,根据以下答案,数据也可能未完全取消设置:
如注释中所述,垃圾回收器移动的数组可能会在内存中留下数据的杂散副本。我相信这是特定于实现的 - 垃圾收集器可能会清除所有内存,以避免此类事情。即使有,char[] 仍然有一段时间包含实际字符作为攻击窗口。
如果编译器决定优化memset
,则 C/C++ 中也存在类似的问题。根据 11.4。特别保护用户内存中的机密(密码和密钥):
Andy Polyakov的一篇Bugtraq帖子(2002年11月7日)报告说,C/C++编译器gcc版本3或更高版本,SGI MIPSpro和Microsoft编译器消除了对旨在覆盖机密的memset的简单内联调用。这是 C 和 C++ 标准允许的。其他 C/C++ 编译器(例如低于版本 3 的 gcc)在所有优化级别都保留了对 memset 的内联调用,这表明该问题特定于编译器。简单地声明目标数据是易失性的并不能对所有编译器都有帮助;MIPSpro和Microsoft编译器都忽略了简单的"挥发"。简单地"触摸"秘密数据的第一个字节也无济于事;他发现 MIPSpro 和 GCC>=3 巧妙地只取消了第一个字节,而让其余部分保持不变(这实际上是相当聪明的——问题是编译器的聪明干扰了我们的目标)。