在Java中,存储密码的旧方法(例如密码)是使用char[]
,因为您可以在完成后覆盖其数据。然而,由于垃圾收集器在重新组织堆时会复制内容,因此这被证明是不安全的。在某些体系结构中,可能会释放页面,并且当其他程序分配同一页面时,秘密将保留。
这非常难看,但是如果秘密存储在Thread的run
方法的堆栈上呢?仍需要注意优雅地终止线程,以便它可以将其数据清零,但这个问题也以旧方式出现。
我立即看到的一个主要问题是我无法想到一种安全的方法来获取数据进出容器。您可以通过使用内部缓冲区非常小的流来最小化泄露秘密的可能性,但最终会遇到与char[]
相同的问题。 [编辑:单个private static byte
成员和一个标志是否有效?虽然这会限制每个ClassLoader一个秘密。这增加了更多的丑陋,但它可能很容易隐藏在一个写得很好的界面背后。]
所以我真的有很多问题。
堆栈比这些类型的攻击更安全吗?是否有任何纯Java机制以对这个问题有用的方式在两个不同的堆栈帧之间执行堆栈到堆栈的复制?如果没有,JVM甚至会在字节码中支持这种类型的操作吗?
[编辑:在人们过分担心之前,这更像是一次思考实验。我完全无意'在生产中测试'或在任何当前项目中使用它。我意识到我所说的内容真的很难看,可能非常笨重,并且可以对抗整个JVM结构。我只是对它是否有可能感兴趣,它是否真正实现了我的目标,以及实现它所需要的英雄主义。]
答案 0 :(得分:12)
我会使用直接的ByteBuffer。它使用的内存不会被复制,只能在ByteBuffer生命周期的一个地方使用。 BTW不使用clear(),因为这只是重置位置。您可以使用
覆盖它bb.clear();
while(bb.remaining() >= 8) bb.putLong(0);
while(bb.remaining() > 0) bb.put((byte) 0);
堆栈比这些类型的攻击更安全吗?
我不这么认为。
是否有任何纯Java机制以对这个问题有用的方式在两个不同的堆栈帧之间执行堆栈到堆栈的复制?
您可以将密码存储为一个或两个long
s。
如果没有,JVM是否会在字节码中支持这种类型的操作?
字节代码旨在支持Java,并且只比您在Java中所做的更多。
我只是对它是否有可能感兴趣,它是否真正实现了我的目标,以及它需要什么样的英雄才能实现它
按照我的建议使用直接的ByteBuffer。 ;)