Java 11 - 如何在JVM和系统内存中覆盖敏感信息(也许使用System.gc()?)

11 浏览
0 Comments

Java 11 - 如何在JVM和系统内存中覆盖敏感信息(也许使用System.gc()?)

问题:如何在Java中强制覆盖系统内存 - 更具体地说:当安全密钥不能在内存中停留超过几秒钟时:无论是在JVM内存中还是在操作系统内存中?\n我尝试过的方法:修改Java垃圾收集器的实现,以确保它会使用随机字节覆盖对象,而不仅仅是释放它们。然而:\n我读到的关于System.gc()的所有内容都告诉我,我永远不能真正依赖它,并且不应该在生产中使用它。然而,如果我知道我使用的是特定的JVM呢?如果我知道我想使用带有Java 11的OpenJDK,并且我配置了JVM使用特定的GC实现(以不让JVM选择GC),那该怎么办呢?\n问题1:\n那么我是否可以确保System.gc()将100%触发垃圾收集?\n问题2:\n我能否找出System.gc()被调用和实际垃圾收集开始之间的最长持续时间?这是问题的一个重要部分!我只能找到有关垃圾收集效率本身的答案(例如吞吐量与停顿时间之间的比较),但这不是这个问题的答案。(阅读整个文档)\n问题3:\n如果修改垃圾收集器的想法远远是在内存中安全覆盖各种敏感Java对象的最糟糕的想法,那么我如何以其他方式在内存中覆盖这些对象呢?在Java中是否可能实现?能否直接在Java代码中删除和覆盖这些对象,类似于在C/C++中释放对象?\n是否有其他可能性,可能不是在Java之外的地方,可以在内存中覆盖每个此类敏感信息的出现,这必须在Java对象不再使用时尽快触发?\n迄今为止的研究:\n

\n正如您所看到的,除了官方文档之外,这些都是相当旧的问题,所以:\n问题4:\n是否有关于System.gc()是否与10年前相同的新见解可用?谢谢!\n*编辑:\n对于那些可以使用字节数组的情况,我已经使用了字节数组。问题是关于具有不同字段和属性的更复杂的Java对象,它们必须在内存中完全清除。

0
0 Comments

问题的出现原因:在Java中,当敏感信息存储在复杂的Java对象或类中时,简单地使用垃圾回收机制(System.gc())来覆盖敏感信息是不可靠的。首先,垃圾回收器可能会在对象的生命周期中创建对象的副本,并且这些副本仍然存在于未使用的内存中。其次,优化的JVM可能会检测到您在之后没有使用对象,因此会消除所有过时的写操作。

解决方法:为了覆盖敏感信息,可以将安全密钥存储在byte[]或其他原始数组中,并在读取密钥后将数组置零。这样可以确保byte[] key被完全覆盖。但是,对于存储在复杂Java对象/类中的密钥,则无法仅仅依靠byte数组。一种解决方法是使用Unsafe.allocateMemory()和Unsafe.freeMemory()来分配和释放内存,但是从Java 9开始,JVM正在逐渐淘汰Unsafe类。

完整文章如下:

假设您可以将安全密钥存储在byte[]或其他原始数组中,那么在读取密钥后将数组置零应该足够:

for (int i = 0; i < key.length; i++) {
  key[i] = 0;
}

上述代码将确保byte[] key被完全覆盖。在这里依赖垃圾回收机制是不可靠的,因为它是不可预测的。

感谢您的回答!我已经在可以直接存储在byte数组中的密钥上使用了这种方法。也许我应该提到,问题是关于更复杂的Java对象/类,不能仅依赖于byte数组。对于这种情况,有没有其他的解决方法呢?

没有保证这种方法能够起作用。首先,分代垃圾回收器可能在对象的生命周期中创建了对象的副本,这些副本仍然存在于未使用的内存中。其次,优化的JVM可能会检测到您在之后没有使用对象,因此会消除所有过时的写操作。

谢谢!这一点非常关键!

我想您可以尝试使用Unsafe.allocateMemory()和Unsafe.freeMemory()来分配和释放内存,但是据我了解,JVM正在逐渐淘汰Unsafe类。

谢谢您的建议,我会研究一下这些方法!

0