如何确保 Java 对象(包含加密材料)被归零?
我担心的是,由垃圾收集器管理的加密密钥和秘密可能会在内存中复制和移动,而不进行归零。
作为一种可能的解决方案,是否足以:
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 进程空间,您应该找不到找到该密钥。
My concern is that cryptographic keys and secrets that are managed by the garbage collector may be copied and moved around in memory without zeroization.
As a possible solution, is it enough to:
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();
}
}
// ...
}
EDIT: Please note that my issue is regarding not only zeroization of the official (referenced) copy of the object, but also any stale copies the garbage collector may have made while it shuffles memory around for space and speed efficiency.
The simplest example is the mark-and-sweep GC, where objects are marked as 'referenced' and then all those objects are copied to another region. The rest are then garbage and so they are collected. When the copy happens, that might leave residual key data that isn't being managed anymore by the garbage collector (because the 'official' data is in the new region).
A litmus test for this would be if you use a key in the crypto module, zeroize the key, then inspect the entire JVM process space, you should not find that key.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
Java 加密扩展参考指南建议始终使用字符数组而不是字符串作为密码,以便之后可以将它们归零。他们还提供了如何操作的代码示例你可以实现它。
The Java Cryptography Extension Reference Guide advises always using character arrays instead of strings for passwords so that they can be zeroed afterwards. They also provide a code example of how you could implement it.
最好的选择是在 NIO 中使用
allocateDirect
。在一个理智的实施中,不应该移动它。但它可能有资格调出到磁盘(我猜你可以轮询它)和休眠。You best bet is to use
allocateDirect
in NIO. On a sane implementation, that should not be moved about. But it'll probably be eligible for paging out to disk (you could poll it, I guess) and hibernation.那么如果内存中的数据在特定时间没有被覆盖怎么办?如果您不得不担心攻击者读取您计算机的内存,那么这就是问题所在,而不是他在何时可以找到什么。
您担心什么实际攻击场景(如果密钥留在 JVM 内存中的某个位置可能会造成严重问题)?如果攻击者可以查看 JVM 的内存,那么他也可以在您仍在使用这些密钥时捕获它们。
如果您担心以普通用户身份在系统上运行的攻击者会获取 JVM 丢弃的内存:据我所知,所有现代操作系统都会用零覆盖新分配的内存。
So what if the data in memory is not overwritten at a specific time? If you have to worry about an attacker reading your machine's memory, that's the problem, not what he could find there at what time.
What actual attack scenario are you worried about where keys left somwhere in the memory of a JVM could be a serious problem? If an attacker can look at the JVM's memory, he can just as well catch those keys while you're still using them.
And if you're worried about an attacker running as a regular user on the system getting hold of memory discarded by the JVM: AFAIK all modern OSs overwrite newly allocated memory with zeroes.
因此,我从 @jambjo 和 @james 得出的结论是,我确实无法采取任何措施来防止密钥被复制和下落不明。
作为开发人员,最好的策略是将加密库放入 C(或任何其他非托管语言)中并在那里实现您的东西。
如果其他人能提出更好的解决方案,我将非常愿意接受他们的答案。
So I've come to the conclusion, from @jambjo and @james, that there really isn't anything I can do to prevent keys from being copied and becoming unaccounted for.
The best strategy, as a developer, would be to drop the crypto library down into C (or any other non-managed language) and implement your stuff there.
I would be more than willing to accept an answer from someone else if they could come up with a better solution.