我的团队交出了一些服务器端代码(在Java中),生成随机令牌,我有一个关于相同的问题
这些令牌的用途相当敏感——用于会话id、密码重置链接等。所以它们确实需要加密随机,以避免有人猜测它们或强行使用它们。令牌是一个“长”,所以它是64位长。
代码目前使用java.util.Random类来生成这些令牌。java.util.Random的文档清楚地说明了以下内容:
java.util.Random的实例不是加密安全的。相反,可以考虑使用securerrandom来获得一个加密安全的伪随机数生成器,以供对安全敏感的应用程序使用。
然而,代码目前使用java.util.Random的方式是这样的——它实例化java.security. securerrandom类,然后使用securerrandom . nextlong()方法来获得用于实例化java.util.Randomclass的种子。然后它使用java.util.Random.nextLong()方法生成令牌。
所以我现在的问题是——考虑到java.util.Random是使用java.security.SecureRandom进行播种的,它仍然是不安全的吗?我是否需要修改代码,以便它专门使用java.security. securerrandom来生成令牌?
目前,代码种子在启动时是随机的
标准的Oracle JDK 7实现使用所谓的线性同余生成器在java.util.Random中生成随机值。
摘自java.util.Random源代码(JDK 7u2),摘自protected int next(int bits)方法的注释,该方法生成随机值:
这是一个线性同余伪随机数发生器,如
由D. H. Lehmer定义,Donald E. Knuth描述
计算机编程艺术,第3卷:
半数值算法,3.2.1节。
线性同余生成器的可预测性
Hugo Krawczyk写了一篇关于如何预测这些lcg的很好的论文(“如何预测同分生成器”)。如果你足够幸运并且感兴趣,你还可以在网上找到一个免费的、可下载的版本。还有更多的研究清楚地表明,您永远不应该将LCG用于安全关键目的。这也意味着你的随机数现在是可预测的,这是你不希望会话id之类的东西。
如何打破一个线性同余发生器
攻击者必须等待LCG在一个完整的周期后重复的假设是错误的。即使有一个最优周期(递归关系中的模量m),也很容易在比完整周期更短的时间内预测未来的值。毕竟,这只是一堆需要解决的模方程,只要你观察到LCG的足够输出值,这就变得很容易了。
安全性不会因为“更好”的种子而提高。不管你是使用SecureRandom生成的随机值,还是通过多次掷骰子生成该值,这都无关紧要。
攻击者只需根据观察到的输出值计算种子。在java.util.Random的情况下,这比2^48的时间要少得多。不相信的人可以试试这个实验,它表明你可以预测未来的随机输出,在大约2^16的时间内只观察到两个(!)输出值。现在,在现代计算机上预测随机数的输出甚至不需要一秒钟。
结论
替换当前代码。专门使用securerrandom。那么至少你有一点保证,结果将是难以预测的。如果您想要加密安全的PRNG的属性(在您的情况下,这就是您想要的),那么您必须只使用SecureRandom。聪明地改变它应该使用的方式几乎总是会导致一些不太安全的事情……
标准的Oracle JDK 7实现使用所谓的线性同余生成器在java.util.Random中生成随机值。
摘自java.util.Random源代码(JDK 7u2),摘自protected int next(int bits)方法的注释,该方法生成随机值:
这是一个线性同余伪随机数发生器,如
由D. H. Lehmer定义,Donald E. Knuth描述
计算机编程艺术,第3卷:
半数值算法,3.2.1节。
线性同余生成器的可预测性
Hugo Krawczyk写了一篇关于如何预测这些lcg的很好的论文(“如何预测同分生成器”)。如果你足够幸运并且感兴趣,你还可以在网上找到一个免费的、可下载的版本。还有更多的研究清楚地表明,您永远不应该将LCG用于安全关键目的。这也意味着你的随机数现在是可预测的,这是你不希望会话id之类的东西。
如何打破一个线性同余发生器
攻击者必须等待LCG在一个完整的周期后重复的假设是错误的。即使有一个最优周期(递归关系中的模量m),也很容易在比完整周期更短的时间内预测未来的值。毕竟,这只是一堆需要解决的模方程,只要你观察到LCG的足够输出值,这就变得很容易了。
安全性不会因为“更好”的种子而提高。不管你是使用SecureRandom生成的随机值,还是通过多次掷骰子生成该值,这都无关紧要。
攻击者只需根据观察到的输出值计算种子。在java.util.Random的情况下,这比2^48的时间要少得多。不相信的人可以试试这个实验,它表明你可以预测未来的随机输出,在大约2^16的时间内只观察到两个(!)输出值。现在,在现代计算机上预测随机数的输出甚至不需要一秒钟。
结论
替换当前代码。专门使用securerrandom。那么至少你有一点保证,结果将是难以预测的。如果您想要加密安全的PRNG的属性(在您的情况下,这就是您想要的),那么您必须只使用SecureRandom。聪明地改变它应该使用的方式几乎总是会导致一些不太安全的事情……