【问题标题】:How to clear content of java.security.Key?如何清除 java.security.Key 的内容?
【发布时间】:2014-09-03 11:15:02
【问题描述】:

当您在 Java 应用程序中使用敏感数据时,通常建议您使用原始类型 - 例如使用 char[] 而不是 String ...

但是对于加密密钥,我们通常需要使用 java.security.Key 对象,因为这是 JCE 提供者使用的。密钥通常是非常敏感的信息,我们希望能够最小化可能的攻击窗口 - 即尽可能晚地创建密钥对象,进行加密/解密/签名,然后尽快清除对象.但是 Key 没有提供任何方法来促进这种清除。

目前我们这样做的方式是将密钥保存在字节数组中并在使用它之前初始化 Key 对象,Key 立即超出范围以符合垃圾收集的条件,我们也立即清除字节数组.但这似乎不是很优雅......它还填充了在我们的接口中创建了一个二分法——一些接受字节数组,一些接受 Key 对象,这有点乱。

我知道 Java 没有提供任何通用机制来从内存中清除对象,但我想问是否有专门针对 Keys 的东西。或者,是否有其他方法可以最小化 Keys 的攻击窗口?

谢谢。

【问题讨论】:

  • 不,没有专门针对键的。 Java 不是实现需要安全内存的软件的语言。你能做的最好的就是在本机代码中实现最小的核心功能并使用 JNI 来访问此代码。
  • 还有密钥材料被复制的风险,所以即使你清除了你的对象,它仍然可能在内存中的其他地方。我以前在 Java 中看过这个,但无法找到真正保证关键材料被擦除的方法。即使您使用 JNI,您也需要对本机加密实现相当了解才能保证任何事情。不过,它可以通过安全硬件相当容易地完成,而且还有一些加密技术,如多方计算,可以减轻受感染客户端的影响(但这可能超出了这个问题的范围)。

标签: java security cryptography


【解决方案1】:

升级到 Java 8,其中 SecretKeyRSAPrivateKey 实现 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 实现SecretKeyDestroyable。不要忘记销毁MyAESKey 的输入。对于 Java 7 及更低版本,您当然可以对自己的 MyDestroyable 接口使用类似的方法。

我知道的唯一其他方法是使用使用安全令牌(HSM / TPM / 智能卡等)的提供程序,其中密钥不会离开设备。在这种情况下,密钥可能也不会被销毁,但至少不可用。

使用本机代码(使用正确类型的内存)的提供程序也可能允许破坏关键数据。但即使在 VM 之外,也很难确保关键数据不会留在 RAM 或(交换)磁盘中的任何位置。

【讨论】:

    猜你喜欢
    • 2019-05-12
    • 2010-12-19
    • 2019-11-13
    • 1970-01-01
    • 2016-01-18
    • 1970-01-01
    • 2015-05-04
    • 2014-01-07
    • 1970-01-01
    相关资源
    最近更新 更多