我担心的是,垃圾收集器管理的加密密钥和秘密可能会被复制并在内存中移动而不会出现零化。
作为一种可能的解决方案,它足以:
public class Key {
private char[] key;
// ...
protected void finalize() throws Throwable {
try {
for(int k = 0; k < key.length; k++) {
key[k] = '\0';
}
} catch (Exception e) {
//...
} finally {
super.finalize();
}
}
// ...
}
编辑:请注意,我的问题不仅是对象的官方(引用)副本的归零,而且还有垃圾收集器在为存储空间和速度效率而改变内存时可能产生的任何过时副本。
最简单的例子是标记和扫描GC,其中对象被标记为“引用”,然后所有这些对象被复制到另一个区域。其余的都是垃圾,所以他们被收集。当副本发生时,可能会留下垃圾收集器不再管理的剩余密钥数据(因为“官方”数据位于新区域中)。
对此进行的试金石是,如果您在加密模块中使用密钥,将密钥归零,然后检查整个JVM进程空间,则不找到该密钥。
答案 0 :(得分:4)
Java Cryptography Extension Reference Guide建议始终使用字符数组而不是密码字符串,以便以后可以将它们归零。它们还提供了how you could implement it的代码示例。
答案 1 :(得分:1)
最好的办法是在NIO中使用allocateDirect
。在一个理智的实现,不应该移动。但它可能有资格分页到磁盘(你可以轮询它,我猜)和休眠。
答案 2 :(得分:1)
那么如果内存中的数据没有在特定时间被覆盖?如果你不得不担心攻击者正在读取你机器的内存,那是问题,而不是他在那个时候能找到的那个。
实际的攻击场景你担心JVM内存中的密钥可能是一个严重的问题吗?如果攻击者可以查看JVM的内存,他也可以在您使用它们的同时捕获这些密钥。
如果您担心在系统上以普通用户身份运行的攻击者获取JVM丢弃的内存:AFAIK所有现代操作系统都会用零覆盖新分配的内存。
答案 3 :(得分:0)
所以我从@jambjo和@james得出结论,我无法做任何事情来防止密钥被复制并成为下落不明的。
作为开发人员,最好的策略是将加密库放到C(或任何其他非托管语言)中并在那里实现你的东西。
如果他们想出更好的解决方案,我会非常愿意接受其他人的回答。