使用 JVM 的受保护字符串和内存持久性



>上下文

我最近有一个密码学讲座,我们讨论了内存中关键元素的持久性。通常,C/C++库 Libsodium 建议清除任何包含敏感信息的缓冲区,例如机密 (ref)。我知道GuardedString由字节数组支持,文档建议调用该方法dispose一旦不再使用存储的密钥,就会使用Arrays.fill填充字节数组。

问题

JVM是否保证字节数组的值在被覆盖时消失,或者在某些情况下原始值可能保留在内存中?例如,未使用/未引用的StringJava 字符串池中保存,直到触发垃圾回收。对于其他类型的缓存或机制,是否有类似的缓存或机制,例如字节数组,可能会破坏应从GuardedString中释放的机密?JVM的规格中的任何参考?

非常感谢 !

在Java中,通常使用数组而不是Stringchar[]因为这允许手动将数组中的数据归零。

但是,即使这样,根据以下答案,数据也可能未完全取消设置:

如注释中所述,垃圾回收器移动的数组可能会在内存中留下数据的杂散副本。我相信这是特定于实现的 - 垃圾收集器可能会清除所有内存,以避免此类事情。即使有,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 巧妙地只取消了第一个字节,而让其余部分保持不变(这实际上是相当聪明的——问题是编译器的聪明干扰了我们的目标)。

最新更新