JVM的GuardedString和内存持久性

时间:2019-04-03 19:44:36

标签: java cryptography jvm internals

上下文

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

问题

JVM是否保证在重写时字节数组的值不存在,或者在某些情况下原始值是否可以保留在内存中?例如,未使用/未引用的String会保存在 Java字符串池中,直到触发垃圾回收为止。是否有类似的缓存或其他类型的机制(例如字节数组)可以危及应从GuardedString处理的秘密? JVM规范中有任何参考吗?

非常感谢!

1 个答案:

答案 0 :(得分:1)

在Java中,通常会使用char[]数组而不是String,因为这样可以手动将数组中的数据清零。

尽管如此,根据this answer,数据可能仍未完全取消设置:

  

如评论中所述,垃圾回收器移动的数组可能会将数据的零散副本保留在内存中。我相信这是特定于实现的-垃圾收集器可能会清除所有内存,以免发生这种情况。即使这样做,仍然有一段时间char []包含实际角色作为攻击窗口。

如果编译器决定优化memset,则C / C ++中存在类似的问题。根据{{​​3}}:

  

安迪·波利亚科夫(Andy Polyakov)的Bugtraq帖子(2002年11月7日)报道,C / C ++编译器的gcc版本3或更高版本,SGI MIPSpro和Microsoft编译器消除了旨在覆盖机密的简单内联调用memset。 C和C ++标准允许这样做。其他C / C ++编译器(例如gcc低于版本3)在所有优化级别上都保留了对memset的内联调用,这表明问题是特定于编译器的。仅仅声明目标数据是易变的,并不能对所有编译器都有用。 MIPSpro和Microsoft编译器都忽略了简单的“挥发”。仅仅“触摸”机密数据的第一个字节也无济于事;他发现MIPSpro和GCC> = 3巧妙地仅使第一个字节无效,而其余部分则保持不变(实际上是非常聪明的-问题在于编译器的聪明之处正在干扰我们的目标)。