我想就Java中SecureRandom的常见神话,安全性与性能权衡问题进行讨论。
我已经在互联网上研究了一段时间,并且我将以下信息放在一起。我希望这里的人帮助我确认我得到了什么,并希望得到一些关于实际选择实施的想法。
基本上这里是SecureRandom的一些最受欢迎和最全面的文章:
正确使用Java的SecureRandom: http://www.cigital.com/justice-league-blog/2009/08/14/proper-use-of-javas-securerandom/
使用Java的SecureRandom时的问题: http://www.cigital.com/justice-league-blog/2014/01/06/issues-when-using-java-securerandom/
使用SecureRandom类: http://moi.vonos.net/java/securerandom/
并且,Sun的官方"坦白" Java 8中的错误/混淆和建议发布: http://openjdk.java.net/jeps/123
现在Java 8已经出来了,老实说,通过查看文档,我不确定实际修复得多好些: http://docs.oracle.com/javase/8/docs/api/java/security/SecureRandom.html
毕竟,这就是我得到的(请帮助我看看我是否对它们进行了分类):
像Amit Sethi这样的人建议使用指定的实例化,例如:SecureRandom sr3 = SecureRandom.getInstance(" SHA1PRNG"," SUN"),实际上,Sun告诉我们这将结束总是从/ dev / random(???)读取,这意味着它可能会阻止每次调用。与使用新的SecureRandom()相反,它将始终从/ dev / urandom读取,除非调用generateSeed()。见
http://bugs.java.com/view_bug.do?bug_id=6202721
这是否意味着"新的SecureRandom()"在当前的Java中仍然是首选吗?我发现没有多少其他文件明确说明上述观点,所以我想知道这是否仍然存在?
现在,如果"新的SecureRandom()"是选择,并将导致永不阻止呼叫,那么我认为我应该做的定期重播应该是:
使SecureRandom成为类中的静态实例,并让另一个Executor线程定期调用generateSeed(),因此即使调用阻塞,它也不会影响我的应用程序中的主请求处理线程。这听起来像是一种很好的方式吗?
真的很感谢任何Java和加密专家在这里阐明这个问题。 谢谢!
编辑: 这里另一个有用的线索似乎支持我的猜测:https://bugs.openjdk.java.net/browse/JDK-4705093
答案 0 :(得分:4)
编辑 :首先;如果/dev/random
或/dev/urandom
阻止,首先尝试修复该特定问题是有意义的。下面的解决方案是尝试修复Java本身的SecureRandom
,因此它不太依赖于这些特殊设备。
使SecureRandom成为类中的静态实例,并让另一个Executor线程定期调用generateSeed(),因此即使调用阻塞,它也不会影响我的应用程序中的主请求处理线程。这听起来像是一种很好的方式吗?
不,在这种情况下,您应该使用nextBytes()
,因为内部呼叫generateSeed()
使用种子信息的原始供应商。换句话说,您也可以创建一个单独的SecureRandom
实例。请注意,只要您的SecureRandom
实例具有足够高的状态和良好的支持算法,就不需要经常重新设置(因为它不太可能创建一个循环)。如果您需要更高的熵,请每次生成一个新的随机类,或使用SecureRandom.getInstanceStrong()
检索的随机类。
使用默认new SecureRandom()
可能是最好的。通常,您应始终为加密算法提供精确的算法名称(例如"AES/CBC/PKCS5Padding"
),但对于安全的随机功能,最好让系统确定哪种算法最佳。如果要更改任何内容,请通过命令行构造进行更改,并确保在Unix系统上可以使用/dev/urandom
。
如果您仍然遇到阻止问题,请创建一个中央系统播种SecureRandom
。使用nextBytes()
创建新的种子材料,并使用SecureRandom(byte[] seed)
构造函数将其提供给新的SecureRandom
。只有new SecureRandom()
无法处理这种情况时才应使用此方法。
尽管现在通过使用构造函数显式提供初始种子,但构造函数本身并不保证它仅用于为RNG播种。然而,它可能可能,因此它不太可能阻止。 SecureRandom
is thread safe因此您无需同步对其的访问权限。
使用新的Java 8 SecureRandom.getInstanceStrong()
更多可能会阻止。我推测他们已经添加以使默认实例非阻塞。 RSA密钥对生成通常需要大量的熵,因此很可能返回做的实例使用对/dev/random
的阻塞调用。
总而言之,在特殊情况下使用SecureRandom
仍然相当肮脏。幸运的是,这只是一个非常有限的用例问题。