Insecure Randomness 不安全的随机数

Insecure Randomness

Abstract

标准的伪随机数生成器不能抵挡各种加密攻击。

Explanation

在对安全性要求较高的环境中,使用一个能产生可预测数值的函数作为随机数据源,会产生 Insecure
Randomness 错误。 电脑是一种具有确定性的机器,因此不可能产生真正的随机性。 伪随机数生成器
(PRNG) 近似于随机算法,始于一个能计算后续数值的种子。 PRNG 包括两种类型: 统计学的 PRNG 和密
码学的 PRNG。 统计学的 PRNG 可提供有用的统计资料,但其输出结果很容易预测,因此数据流容易复制。
若安全性取决于生成数值的不可预测性,则此类型不适用。 密码学的 PRNG 通过可产生较难预测的输出结果
来应对这一问题。 为了使加密数值更为安全,必须使攻击者根本无法、或极不可能将它与真实的随机数加以
区分。 通常情况下,如果并未声明 PRNG 算法带有加密保护,那么它有可能就是一个统计学的 PRNG,不应
在对安全性要求较高的环境中使用。
示例: 下面的代码可利用统计学的 PRNG 为购买产品后仍在有效期内
的收据创建一个 URL。
String GenerateReceiptURL(String baseUrl) {
    Random ranGen = new Random();
    ranGen.setSeed((new Date()).getTime());
    return(baseUrl + Gen.nextInt(400000000) + ".html");
}

 

这段代码使用 Random.Next() 函数为由其产生的收据页面生成“唯一”的标识符。 因为
Random.nextInt() 是一个统计学 PRNG,攻击者很容易就能猜到由它生成的字符串。 尽管收据系统的底
层设计也存在错误,但如果使用了一个不生成可预测收据标识符的随机数生成器(如密码学的 PRNG),会
更安全一些。

Recommendation

当不可预测性至关重要时,如大多数对安全性要求较高的环境都采用随机性,这时可以使用密码学的 PRNG
。 不管选择了哪一种 PRNG,都要始终使用带有充足熵的数值作为该算法的种子。 (诸如当前时间之类的数
值只提供很小的熵,因此不应该使用。) Java 语言在 java.security.SecureRandom 中提供了一个加
密 PRNG。 就像 java.security 中其他以算法为基础的类那样,SecureRandom 提供了与某个特定算法
集合相关的包,该包可以独立实现。 当使用 SecureRandom.getInstance() 请求一个 SecureRandom
实例时,您可以申请实现某个特定的算法。 如果算法可行,那么您可以将它作为 SecureRandom 的对象使
用。 如果算法不可行,或者您没有为算法明确特定的实现方法,那么会由系统为您选择 SecureRandom 的
实现方法。 Sun 在名为 SHA1PRNG 的 Java 版本中提供了一种单独实现 SecureRandom 的方式,Sun 将其
描述为计算: “SHA-1 可以计算一个真实的随机种子参数的散列值,同时,该种子参数带有一个 64 比特的计
算器,会在每一次操作后加 1。 在 160 比特的 SHA-1 输出中,只能使用 64 比特的输出 [1]。” 然而,文档中
有关 Sun 的 SHA1PRNG 算法实现细节的相关记录很少,人们无法了解算法实现中使用的熵的来源,因此也并
不清楚输出中到底存在多少真实的随机数值。 尽管有关 Sun 的实现方法网络上有各种各样的猜测,但是有一
点无庸置疑,即算法具有很强的加密性,可以在对安全性极为敏感的各种内容中安全地使用。

解决办法
采用更加安全的SecureRandom来替换Random。
 
posted @ 2021-05-13 15:40  Shinoburedo  阅读(1064)  评论(0编辑  收藏  举报