上下文
我最近举行了一次密码学讲座,我们讨论了内存中关键元素的持久性。通常,C / C ++库Libsodium建议清除包含敏感信息(例如机密(ref))的所有缓冲区。我知道GuardedString
由字节数组支持,并且文档建议一旦不再使用存储的机密,则调用方法dispose
,该方法使用Arrays.fill
填充字节数组。
问题
JVM是否保证在重写时字节数组的值不存在,或者在某些情况下原始值是否可以保留在内存中?例如,未使用/未引用的String
会保存在 Java字符串池中,直到触发垃圾回收为止。是否有类似的缓存或其他类型的机制(例如字节数组)可以危及应从GuardedString
处理的秘密? JVM规范中有任何参考吗?
非常感谢!
答案 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巧妙地仅使第一个字节无效,而其余部分则保持不变(实际上是非常聪明的-问题在于编译器的聪明之处正在干扰我们的目标)。