建议不要使用math.radom生成随机数加密

57 阅读2分钟

先说结论

使用 crypoto。getRandomValue生成随机数

// 实现math.radom功能
function radomFloat() {
  // 生成32位随机数
  const fooArray = new Uint32Array(1);
  // 最大值  2^32 - 1
  const maxUint32 = 0xffffffff;
  // 用最大可能的值来除
  return crypto.getRandomValues(fooArray)[0] / maxUint32;
}
console.log(radomFloat()); // 0.09718604364832538

原理

Web Cryptography API引人 CSPRNG,这个 CSPRNG 可以通过 crypto.getRandomvalues ()在全scrypto 对象上访。与 Math.random()返回一个介于0和1之间的浮点数不同,getRandomValues ()会把随机值写人作为参数传给它的定型数组。定型数组的类不重要,因为底层缓冲区会被随机的二进制位填充。

补充

红宝书是这么说的 Math.radom()

在需要生成随机值时,很多人会使用Mwath.random()。这个方法在浏览器中是以伪随机数生成器(PRNG, PseudoRandom Number Gelerator)方式实现的。所谓“伪”指的是生成值的过程不是真的随机。 PRNG生成的值只是模拟了随机的特性

浏览器的PRNG并未使用真正的随机源,只是对一个内部状态应用了固定算法。每次调用math.radom(),这个内部状态都会被一个算法修改,而结果会被转换为一个新的随机值。由于算法是固定的,其输入只是之前的状态,因此随机数顺序也是确定的。xorshift128+使用128位内部状念,而算法的设计让任何初始状态在重复自身之前都会产生2128-1 个伪随机值。这种循环被称为置换循环(permutation cycle),而这个循环的长度被称为一个周期(period)。很明显,如果攻言翻知道PRNG 的内部状态,就可以预测后续生成的伪随机值。如果开发者无意中使用PRNG生成了私密钥用于加密,则攻击者就可以利用PRNG的这个特性算出私有密。