java.util.Random 和 java.security.SecureRandom 的区别 [英] Difference between java.util.Random and java.security.SecureRandom

查看:37
本文介绍了java.util.Random 和 java.security.SecureRandom 的区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的团队移交了一些生成随机令牌的服务器端代码(Java),我有一个关于相同的问题 -

My team got handed over some server side code (in Java) that generates random tokens and I have a question regarding the same -

这些令牌的用途相当敏感 - 用于会话 ID、密码重置链接等.因此它们确实需要加密随机以避免有人猜测它们或可行地对其进行暴力破解.令牌是一个长",所以它是 64 位长.

The purpose of these tokens is fairly sensitive - used for session id, password reset links etc. So they do need to be cryptographically random to avoid somebody guessing them or brute force them feasibly. The token is a "long" so it is 64 bits long.

代码当前使用 java.util.Random 类来生成这些标记.java.util 的文档.Random 明确声明如下:

The code currently uses the java.util.Random class to generate these tokens. The documentation for java.util.Random clearly states the following:

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

Instances of java.util.Random are not cryptographically secure. Consider instead using SecureRandom to get a cryptographically secure pseudo-random number generator for use by security-sensitive applications.

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

However, the way the code is currently using java.util.Random is this - It instantiates the java.security.SecureRandom class and then uses the SecureRandom.nextLong() method to obtain the seed that is used for instantiating the java.util.Randomclass. Then it uses java.util.Random.nextLong() method to generate the token.

所以我现在的问题 - 鉴于 java.util.Random 是使用 java.security.SecureRandom 播种的,它仍然不安全吗?我是否需要修改代码以使其仅使用 java.security.SecureRandom 来生成令牌?

So my question now - Is it still insecure given that the java.util.Random is being seeded using java.security.SecureRandom? Do I need to modify the code so that it uses java.security.SecureRandom exclusively to generate the tokens?

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

Currently the code seed's the Random once at startup

推荐答案

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

The standard Oracle JDK 7 implementation uses what's called a Linear Congruential Generator to produce random values in java.util.Random.

取自 java.util.Random 源代码 (JDK 7u2),来自对方法 protected int next(int bits) 的评论,这是生成随机值:

Taken from java.util.Random source code (JDK 7u2), from a comment on the method protected int next(int bits), which is the one that generates the random values:

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

This is a linear congruential pseudorandom number generator, as defined by D. H. Lehmer and described by Donald E. Knuth in The Art of Computer Programming, Volume 3: Seminumerical Algorithms, section 3.2.1.

线性同余发生器的可预测性

Hugo Krawczyk 写了一篇关于如何预测这些 LCG 的非常好的论文(如何预测同余生成器").如果您很幸运并且感兴趣,您仍然可以在网上找到它的免费、可下载版本.还有更多研究清楚地表明,您应该永远将 LCG 用于安全关键目的.这也意味着您的随机数现在是可预测的,这是您不希望会话 ID 之类的东西.

Predictability of Linear Congruential Generators

Hugo Krawczyk wrote a pretty good paper about how these LCGs can be predicted ("How to predict congruential generators"). If you're lucky and interested, you may still find a free, downloadable version of it on the web. And there's plenty more research that clearly shows that you should never use an LCG for security-critical purposes. This also means that your random numbers are predictable right now, something you don't want for session IDs and the like.

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

The assumption that an attacker would have to wait for the LCG to repeat after a full cycle is wrong. Even with an optimal cycle (the modulus m in its recurrence relation) it is very easy to predict future values in much less time than a full cycle. After all, it's just a bunch of modular equations that need to be solved, which becomes easy as soon as you have observed enough output values of the LCG.

更好"的种子不会提高安全性.如果您使用 SecureRandom 生成的随机值进行播种,或者甚至通过多次掷骰子产生该值,这都无关紧要.

The security doesn't improve with a "better" seed. It simply doesn't matter if you seed with a random value generated by SecureRandom or even produce the value by rolling a die several times.

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

An attacker will simply compute the seed from the output values observed. This takes significantly less time than 2^48 in the case of java.util.Random. Disbelievers may try out this experiment, where it is shown that you can predict future Random outputs observing only two(!) output values in time roughly 2^16. It takes not even a second on a modern computer to predict the output of your random numbers right now.

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

Replace your current code. Use SecureRandom exclusively. Then at least you will have a little guarantee that the result will be hard to predict. If you want the properties of a cryptographically secure PRNG (in your case, that's what you want), then you have to go with SecureRandom only. Being clever about changing the way it was supposed to be used will almost always result in something less secure...

这篇关于java.util.Random 和 java.security.SecureRandom 的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆