当您在Java应用程序中使用敏感数据时,通常会建议您使用原始类型 - 例如使用char []而不是String ...
但是使用加密密钥我们通常需要使用java.security.Key对象,因为这是JCE提供程序使用的对象。密钥通常是非常敏感的信息,我们希望能够最小化可能的攻击窗口 - 即尽可能晚地创建密钥对象,进行加密/解密/签名然后尽快清除物体。但Key并没有提供任何能够促成这种清算的方法。
目前我们正在以一种方式将密钥保存在字节数组中并在使用之前初始化Key对象,Key立即超出范围以便有资格进行垃圾回收,我们也立即清除字节数组。但这看起来并不优雅......它还填充在我们的接口中创建了一个二分法 - 一些接受字节数组,一些接受Key对象,它有点混乱。
我知道Java并没有提供任何通用机制来清除内存中的对象,但我还在询问是否有针对Keys的内容。或者,是否有其他方法可以最小化密钥的攻击窗口?
感谢。
答案 0 :(得分:5)
升级到Java 8,其中SecretKey
和RSAPrivateKey
实现Destroyable
。但是,快速测试表明,这不适用于AES密钥,也不适用于本地生成的RSA私钥。
以下代码 工作,但它仅在第二个init(!)之后失败,因此请注意可能缓存密钥信息(AES需要子密钥派生,因此子密钥可能会延迟)。在使用后使用单独的(零)密钥重新启动任何密码可能是个好主意。此外,它不能防止VM本身复制数据,例如,在垃圾收集后的内存压缩过程中。
MyAESKey myAESKey = new MyAESKey(new byte[16]);
Cipher aes = Cipher.getInstance("AES");
aes.init(Cipher.ENCRYPT_MODE, myAESKey);
aes.doFinal("owlstead".getBytes());
myAESKey.destroy();
aes.doFinal("owlstead".getBytes());
aes.init(Cipher.ENCRYPT_MODE, myAESKey);
aes.doFinal("owlstead".getBytes());
其中MyAESKey
同时实现SecretKey
和Destroyable
。不要忘记销毁MyAESKey
的输入。您当然可以使用类似的方法,使用您自己的{7}及以下Java MyDestroyable
接口。
我所知道的唯一其他方法是使用使用安全令牌(HSM / TPM /智能卡等)的提供商,其中密钥不会离开设备。在这种情况下,键可能也不会被销毁,但它至少不可用。
使用本机代码(使用正确类型的内存)的提供程序也可能允许销毁关键数据。但即使在VM之外,也许很难确保关键数据不会留在RAM或(交换)磁盘的任何地方。