java.util.Random 和 java.security.SecureRandom 之间的区别

2022-08-31 05:54:48

我的团队交出了一些服务器端代码(在Java中),这些代码可以生成随机令牌,我对此有疑问 -

这些令牌的目的相当敏感 - 用于会话ID,密码重置链接等。因此,它们确实需要加密随机,以避免有人猜测它们或暴力破解它们。令牌是“长”,因此长度为 64 位。

代码当前使用该类来生成这些令牌。的文档清楚地说明了以下内容:java.util.Randomjava.util.Random

java.util.Random 的实例在加密上是不安全的。请考虑使用 SecureRandom 来获取加密安全的伪随机数生成器,以供安全敏感型应用程序使用。

但是,代码当前使用的方式是这样的 - 它实例化类,然后使用该方法获取用于实例化类的种子。然后,它使用方法来生成令牌。java.util.Randomjava.security.SecureRandomSecureRandom.nextLong()java.util.Randomjava.util.Random.nextLong()

所以我现在的问题 - 鉴于正在播种使用,它是否仍然不安全?我是否需要修改代码,以便它专门用于生成令牌?java.util.Randomjava.security.SecureRandomjava.security.SecureRandom

目前,代码种子是启动时的一次Random


答案 1

标准的 Oracle JDK 7 实现使用所谓的线性同余生成器在 中生成随机值。java.util.Random

取自源代码 (JDK 7u2),取自对方法的注释,该方法生成随机值:java.util.Randomprotected int next(int bits)

这是一个线性同余伪随机数生成器,由D. H. Lehmer定义,并由Donald E. Knuth在“计算机编程的艺术,第3卷:半数算法”中描述,第3.2.1节。

线性同余发电机的可预测性

Hugo Krawczyk写了一篇关于如何预测这些LCG的非常好的论文(“如何预测同余发电机”)。如果你很幸运和感兴趣,你仍然可以在网上找到一个免费的,可下载的版本。还有更多的研究表明,您永远不应该将LCG用于安全关键目的。这也意味着您的随机数现在是可预测的,这是您不希望会话ID等的。

如何破坏线性同余发生器

攻击者必须等待LCG在完整周期后重复的假设是错误的。即使有一个最优循环(其递归关系中的模数m),也很容易在比完整周期短得多的时间内预测未来值。毕竟,这只是一堆需要求解的模方程,一旦你观察到足够多的LCG输出值,这就会变得容易。

安全性不会随着“更好”种子的提高而提高。如果您使用由骰子多次滚动生成的随机值进行种子化,甚至通过多次滚动该值来生成该值,这根本无关紧要。SecureRandom

攻击者只需根据观察到的输出值计算种子即可。在 出现 的情况下,这比 2^48 花费的时间要少得多。不信者可能会尝试这个实验,其中表明您可以预测未来的输出,在大约2 ^ 16的时间内只观察到两个(!)输出值。在现代计算机上,现在甚至不需要一秒钟就可以预测随机数的输出。java.util.RandomRandom

结论

替换当前代码。独家使用。那么至少你会有一点保证,结果将很难预测。如果你想要一个加密安全的PRNG的属性(在你的情况下,这就是你想要的),那么你只需要使用。聪明地改变它应该被使用的方式几乎总是会导致一些不安全的东西......SecureRandomSecureRandom


答案 2

随机只有48位,而SecureRandom最多可以有128位。因此,在安全随机中重复的机会非常小。

随机使用 作为种子/或生成种子。因此,如果攻击者知道种子的生成时间,则可以轻松复制它们。但是SecureRandom从您的(它们可以是击键之间的间隔等 - 大多数操作系统收集这些数据将它们存储在文件中 - )并将其用作种子。
因此,如果小令牌大小是可以的(在随机的情况下),您可以继续使用代码而无需任何更改,因为您正在使用SecureRandom来生成种子。但是,如果您想要更大的令牌(不受制于)使用SecureRandom -
如果需要随机尝试,则使用当今的高级CPU,可以在实际时间内打破它。但是,对于安全随机性,将需要尝试,这需要数年才能与当今的先进机器实现收支平衡。

有关更多详细信息,请参阅链接。
编辑
在阅读@emboss提供的链接后,很明显,种子,无论它多么随机,都不应该与java.util.Random一起使用。通过观察输出来计算种子非常容易。

转到 SecureRandom - 使用本机 PRNG(如上面的链接中所示),因为它在每次调用 时都会从文件中获取随机值。这样,观察输出的攻击者将无法辨认任何东西,除非他正在控制文件的内容(这是非常不可能的)
sha1 prng 算法只计算一次种子,如果你的 VM 使用相同的种子运行数月,则可能会被被动观察输出的攻击者破解。

注意 - 如果您调用的速度比操作系统能够将随机字节(熵)写入的速度快,则在使用 NATIVE PRNG 时可能会遇到麻烦。在这种情况下,请使用 SecureRandom 的 SHA1 PRNG 实例,每隔几分钟(或某个间隔),使用 SecureRandom 的 NATIVE PRNG 实例的值来设定此实例的种子。运行这两个并行性将确保您定期使用真正的随机值进行种子设定,同时也不会耗尽操作系统获得的熵。system clockRandom Dataos/dev/random and /dev/urandom in case of linux/solarisbrute force attacks2^482^128/dev/randomnextBytes()/dev/randomnextBytes()/dev/randomnextBytes()