首先随机数最基本的概念是统计学意义上的伪随机数,对于给定的一个样本集,每个元素
出现的概率是大概相似的,只要从人类的视角看上去一组数是随机的,就符合统计学意义
上的伪随机数定义;因为统计学上的伪随机数,在给定随机样本和随机算法的情况下,能
够有效地演算出随机样本的剩余部分,因此统计学上的伪随机数需要得到进一步地安全强
化,密码学安全的伪随机数应运而生;而随机数的最终概念形态,则是真随机数,其定义
是在满足前两个条件的基础上,再增加一个随机样本不可重现的条件。
然而,严格的真随机数是一种非常理想的形态,从真实情况来看,只要给定边界条件,真
随机数其实并不存在。因为无论背景辐射、物理噪音还是抛掷硬币,只要经过非常精密的
观察和测量,都是可以被预测的。但是在这些例子中,实际的边界条件非常复杂,而且是
极难观测的,因此我们可以认为这些条件下产生的随机数是非常接近真随机数的伪随机
数。
随机数的生成
产生随机数的方法被称为随机数生成器(RNG, random number generator)。
在实际应用中我们往往使用伪随机就足够了,这些随机数主要通过一个固定的、可重复的
计算方法生成,这些计算方法经过特殊的设计,使得产生的结果具有类似真随机数的统计
学特征。这种生成的伪随机数一般只是重复的周期比较大的数列,以算法和种子值共同作
用生成。这种生成伪随机数的方法叫伪随机数生成器(PRNG, pseudo-random number
generator),进一步能够生成密码学安全随机数的方法叫密码学伪随机数生成器
(CPRNG, cryptographic pseudo-random number generator)。
从实现的角度来看,伪随机数生成器会在函数内部维护一个状态,每个随机数的诞生,时
都是从这个状态计算出来的,这个状态随着下一个随机数的生成而改变,而第一个状态则
是由种子初始化得到。
无效的随机数 String generateUrl( String baseUrl ) {
Random randomGen = new Random();
randomGen.setSeed((new Date()).getTime());
return (baseUrl + randomGen.nextInt(400000000) + ".html");
} 可以看到,如下代码使用Random.nextInt()函数来生成新的 URL 地址,其种子值由
(new Date()).getTime()生成,该数值为 1970 年 1 月 1 日 00:00:00 GMT 至今的毫
秒数,已经具备较强的随机性和不可预测性。那么,这是否能说明,这段代码已经安全了
呢? 答案并非如此。Random.nextInt()函数是java.util.Random类的成员函数,而
java.util.Random类是一个统计学意义上的伪随机数生成器,因此会更容易被攻击者猜
测到生成的数值,对于安全性敏感的应用,建议使用密码学安全的随机数生成器
java.security.SecureRandom