use*_*973 200 java security random cryptography
我的团队交出了一些生成随机令牌的服务器端代码(用Java),我对此有一个问题 -
这些令牌的目的是相当敏感的 - 用于会话ID,密码重置链接等.所以他们确实需要加密随机,以避免有人猜测它们或蛮力强制它们.令牌是"长",所以它是64位长.
代码当前使用java.util.Random
该类来生成这些令牌.文档([ http://docs.oracle.com/javase/7/docs/api/java/util/Random.html] [1 ])java.util.Random
清楚地说明了以下内容:
java.util.Random的实例不具有加密安全性.相反,请考虑使用SecureRandom来获取加密安全的伪随机数生成器,以供安全敏感应用程序使用.
但是,代码当前使用的方式java.util.Random
是 - 它实例化java.security.SecureRandom
类,然后使用该SecureRandom.nextLong()
方法获取用于实例化java.util.Random
类的种子.然后它使用java.util.Random.nextLong()
方法生成令牌.
所以我现在的问题 - 鉴于java.util.Random
正在使用种子,它仍然是不安全的java.security.SecureRandom
吗?我是否需要修改代码以便它java.security.SecureRandom
专门用于生成令牌?
目前代码种子是Random
启动时的一次
emb*_*oss 229
标准的Oracle JDK 7实现使用所谓的线性同余生成器来生成随机值java.util.Random
.
取自java.util.Random
源代码(JDK 7u2),来自方法的注释,该方法protected int next(int bits)
是生成随机值的方法:
这是一个线性同余伪随机数发生器,由DH Lehmer定义并由Donald E. Knuth在 The Computer of Computer Programming, Volume 3: Seminumerical Algorithms,section 3.2.1中描述.
Hugo Krawczyk写了一篇关于如何预测这些LCG的非常好的论文("如何预测同余发生器").如果您很幸运并感兴趣,您仍然可以在网上找到免费的可下载版本.并且有大量更多的研究清楚地表明,你应该永远使用安全关键目的的LCG.这也意味着您的随机数现在是可预测的,您不需要会话ID等.
假设攻击者必须等待LCG在完整循环后重复才是错误的.即使具有最佳循环(其递归关系中的模量m),也可以在比完整循环少得多的时间内预测未来值.毕竟,它只是需要解决的一堆模块化方程式,一旦您观察到足够的LCG输出值,就会变得容易.
通过"更好"的种子,安全性不会提高.如果您使用随机生成的随机值播种,SecureRandom
或者甚至通过多次掷骰子来生成该值,则无关紧要.
攻击者只需根据观察到的输出值计算种子.在这种情况下,这比2 ^ 48 花费的时间少得多java.util.Random
.不相信者可能会尝试这个实验,在这个实验中,你可以预测未来的Random
输出只能及时观察两个(!)输出值大约2 ^ 16.在现代计算机上甚至不需要一秒钟来预测随机数的输出.
替换您当前的代码.SecureRandom
独家使用.那么至少你会有一点保证结果很难预测.如果你想要加密安全PRNG的属性(在你的情况下,这就是你想要的),那么你必须SecureRandom
只使用.聪明地改变应该使用它的方式几乎总会导致不太安全的东西......
Ash*_*win 72
随机只有48位,而SecureRandom最多可以有128位.因此,在securerandom中重复的可能性非常小.
随机使用system clock
作为种子/或生成种子.因此,如果攻击者知道种子生成的时间,则可以轻松复制它们.但是SecureRandom的需要Random Data
从你的os
(按键等,他们之间可以间隔-大多数操作系统收集这些数据并将其存储在文件- /dev/random and /dev/urandom in case of linux/solaris
),并将其用作种子.
因此,如果小令牌大小没问题(在随机的情况下),您可以继续使用您的代码而无需任何更改,因为您使用SecureRandom来生成种子.但是,如果你想要更大的标记(不能受到brute force attacks
)去的SecureRandom -
在随机只的情况下,2^48
尝试是必须的,与今天先进的CPU的,可以打破它在实际时间.但是对于安全随机的2^128
尝试将是必需的,这将需要数年和数年来与当今的先进机器打破平衡.
有关详细信息,请参阅此链接.
编辑
在阅读@emboss提供的链接后,很明显,种子,无论多么随机,都不应该与java.util.Random一起使用.通过观察输出来计算种子非常容易.
转到SecureRandom - 使用本机PRNG(如上面的链接中所示),因为它/dev/random
为每次调用从文件中获取随机值nextBytes()
.这样,攻击者观察输出将不能够做出来的任何东西,除非他控制的内容/dev/random
文件(这是非常不可能的)
的SHA1 PRNG算法计算的种子只有一次,如果你的虚拟机正在运行几个月使用相同种子,它可能会被一个被动地观察输出的攻击者破解.
注意 - 如果您调用的nextBytes()
速度比您的操作系统能够将随机字节(熵)写入更快/dev/random
,则在使用NATIVE PRNG时可能会遇到麻烦 .在这种情况下,使用SecureRandom的SHA1 PRNG实例并且每隔几分钟(或一些间隔),使用来自nextBytes()
SecureRandom的NATIVE PRNG实例的值来设置此实例.平行运行这两个将确保您定期播种真正的随机值,同时也不会耗尽操作系统获得的熵.
如果java.util.Random.nextLong()
使用相同的种子运行两次,它将生成相同的数字.出于安全原因,您希望坚持使用,java.security.SecureRandom
因为它的可预测性要低得多.
这两个类是相似的,我认为您只需要使用重构工具进行更改Random
,SecureRandom
并且大多数现有代码都可以使用.
归档时间: |
|
查看次数: |
82299 次 |
最近记录: |