JS-获取安全的随机数Crypto.getRandomValues()

1,918 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第6天,点击查看活动详情

前言

JavaScript 中, 通常使用 Math.random 获取随机数;然而在 MDN中,备注着这么一句话:

微信截图_20221010111308.png

也就是说,Math.random 虽然能够满足大多数需要使用随机数的场景,但是不够安全,不能用于处理一些和安全有关的需求。

为何 Math.random 不够安全

根据网络上的资料,Math.random 的实现是基于 XorShift128+算法实现的。

这种算法的随机数并不是在使用时就已经生成的,而是在环境初始化或者缓存的随机数用完时,会生成一个随机数的cache

也就是说,每次使用的随机数其实在一开始就已经存在了,在使用时将其取出而已,如果把随机数的缓存进行更改,那么,随机,就将变成可控的,随机也就失去了意义。

参考文章

使用 Crypto.getRandomValues() 代替

这个方法与 Math.random 相比,它是在调用时才生成随机数的数组,然后使用者从数组获取某一个随机数使用,不用担心被篡改了随机数缓存。同时,因为没有使用缓存,所以 Crypto.getRandomValues() 的性能是比 Math.random 要差一些的。

使用时,比 Math.random 复杂一点;首先,它的参数typedArray,也只能是 typedArray,传入其他数组会报错,无法执行代码;第二,它返回的是一个随机数的数组,需要从数据里面取出数据才能使用。

可以封装成如下函数来模拟 Math.random:

function getSafeRandom (): number {
  return crypto.getRandomValues(new Uint8Array(1))[0] / 256
}

代码中 crypto.getRandomValues(new Uint8Array(1))[0] 表示从 0 ~ 256 随机去一个数字,然后除以 256 缩小其最终取值的值域,将返回一个从 0 ~ 1 之中的数字。