5

我担心的是垃圾收集器管理的加密密钥和机密可能会在内存中复制和移动而无需归零。

作为一种可能的解决方案,是否足以:

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();
    }
  }
  // ...
}

编辑:请注意,我的问题不仅与对象的官方(引用)副本的归零有关,还与垃圾收集器在为空间和速度效率洗牌时可能制作的任何陈旧副本有关。

最简单的例子是mark-and-sweep GC,其中对象被标记为“引用”,然后所有这些对象都被复制到另一个区域。其余的都是垃圾,所以它们被收集起来。当复制发生时,可能会留下垃圾收集器不再管理的剩余密钥数据(因为“官方”数据在新区域中)。

对此的试金石是,如果您在加密模块中使用密钥,将密钥归零,然后检查整个 JVM 进程空间,您应该找不到该密钥。

4

4 回答 4

4

Java Cryptography Extension Reference Guide建议始终使用字符数组而不是字符串作为密码,以便之后可以将它们归零。它们还提供了如何实现它的代码示例。

于 2010-03-23T19:31:39.337 回答
1

你最好的选择是allocateDirect在 NIO 中使用。在一个理智的实施中,这不应该被转移。但它可能有资格分页到磁盘(我猜你可以轮询它)和休眠。

于 2010-03-23T19:36:44.433 回答
1

那么如果内存中的数据在特定时间没有被覆盖怎么办?如果您不得不担心攻击者会读取您机器的内存,那就是问题所在,而不是他在什么时候可以在那里找到什么。

您担心什么实际的攻击场景会导致 JVM 内存中某个地方的密钥可能是一个严重的问题?如果攻击者可以查看 JVM 的内存,他也可以在您仍在使用这些密钥时捕获它们。

而且,如果您担心攻击者在系统上以普通用户身份运行,会获取 JVM 丢弃的内存:AFAIK 所有现代操作系统都会用零覆盖新分配的内存。

于 2010-03-25T15:59:26.883 回答
0

所以我从@jambjo 和@james 得出的结论是,我确实无法采取任何措施来防止密钥被复制和下落不明。

作为开发人员,最好的策略是将加密库放入 C(或任何其他非托管语言)并在那里实现你的东西。

如果他们能提出更好的解决方案,我将非常愿意接受其他人的回答。

于 2010-03-25T15:42:10.647 回答