0
点赞
收藏
分享

微信扫一扫

深入JS getRandomValues和Math.random方法

霍华德 2022-06-20 阅读 84


我们日常开发经常会用到随机数,基本上我接触下来,都是使用 Math.random() 生成的。


例如生成随机ID:


document.body.id = ('_' + Math.random()).replace('0.', '');

请问这样实现有没有问题?


回答:没有问题。


例如随机排序:


[1, 2, 3, 4, 5].sort(_ => Math.random() - .5);

请问这样实现有没有问题?


回答:没有问题。


但是,如果你希望实现加密操作,例如生成密钥,尤其是在 Node.js 服务层,则 Math.random() 就有问题了,会有潜在的安全风险,需要使用 crypto.getRandomValues() 方法。


哦?安全风险?还有个 getRandomValues() 方法?


不急,我们慢慢聊。


二、Math.random的安全风险

提到 Math.random() 的安全风险,有开发人员会说因为 Math.random() 返回的是伪随机数。


这个解释似是而非,和伪随机数没有关系,getRandomValues() 方法返回的也是伪随机数。


还有人说因为 Math.random() 返回的随机值范围不是均匀的,这个回答就不是似是而非了,而是大错特错。

Math.random() 函数返回一个范围0-1的伪随机浮点数,其在 V8 中的实现原理是这样的:


为了保证足够的性能,Math.random() 随机数并不是实时生成的,而是直接生成一组随机数(64个),并放在缓存中。


当这一组随机数取完之后再重新生成一批,放在缓存中。


由于 Math.random() 的底层算法是公开的(xorshift128+ 算法),V8 源码可见,因此,是可以使用其他语言模拟的,这就导致,如果攻击者知道了当前随机生成器的状态,那就可以知道缓存中的所有随机数,那就很容易匹配与破解。


例如抽奖活动,使用 Math.random() 进行随机,那么就可以估算出一段时间内所有的中奖结果,从而带来非常严重且致命的损失。


此时应该使用 getRandomValues() 方法。

举报

相关推荐

0 条评论