别再用 Math.random() 了!使用crypto.getRandomValues()安全替代

AI 概述
Math.random()生成的是伪随机数,基于确定算法和初始种子,存在被预测的风险,ECMAScript 规范不要求其必须密码学安全。更安全的替代方案是crypto.getRandomValues(),它作为密码学安全伪随机数生成器,从操作系统底层的“熵池”获取随机性,不可预测。其用法是填充类型化数组,可封装成函数替代Math.random(),如生成0到1间浮点数的secureRandom()、生成范围内安全随机整数的secureRandomInt()。Math.random()适用于非安全场景,真随机需求应选crypto.getRandomValues()。
目录
文章目录隐藏
  1. Math.random()

别再用 Math.random() 了!使用 crypto.getRandomValues()安全替代

当我们需要一个随机数时,Math.random()几乎是所有人的第一反应。它简单、直接,一行代码就能得到一个 0 到 1 之间的浮点数。

然而,这个信手拈来的函数,却有着致命的缺陷。

Math.random()

Math.random()生成的数字并非真正的随机,而是伪随机。

什么是伪随机?它是由一个确定的算法,根据一个初始值(称为“种子”)计算出来的一系列数字。这个算法本身是公开的,这意味着,如果你知道了初始的“种子”,你就能完全预测出接下来生成的每一个“随机数”。

在早期的浏览器中,这个“种子”甚至可能只是简单的时间戳,使得预测变得非常容易。虽然现代浏览器已经改进了种子的生成方式,使其更难被猜测,但Math.random()的核心机制并没有改变。ECMAScript 规范本身不要求 Math.random() 必须是密码学安全的。

更安全的替代方案:crypto.getRandomValues()

window.crypto是浏览器提供的一套用于密码学操作的 API,而crypto.getRandomValues()就是其中的一员。它是一个密码学安全伪随机数生成器 (CSPRNG)。

Math.random()不同,crypto.getRandomValues()的设计目标就是提供密码学级别的安全性。

它是如何做到“真正随机”的?

它直接从操作系统底层获取高质量的“熵 (Entropy)”。这些熵的来源是不可预测的物理事件,例如:

  • 鼠标移动的精确时机和轨迹;
  • 键盘输入的时机;
  • 硬件设备产生的微小噪声;
  • 网络数据包的到达时间。

操作系统将这些不可预测的事件混合成一个“熵池”,crypto.getRandomValues()正是从这个池中获取随机性,使其生成的数值在统计学上是真正不可预测的。

如何使用 crypto.getRandomValues()?

它的用法与Math.random()有所不同。它不是直接返回一个数字,而是用于填充一个类型化数组 (Typed Array),如Uint8ArrayUint32Array

基础用法:

// 创建一个包含 10 个字节的数组
const randomBytes = new Uint8Array(10);

// 用密码学安全的随机值填充它
crypto.getRandomValues(randomBytes);

console.log(randomBytes); // 输出: Uint8Array(10) [185, 20, 248, 119, ...]

这看起来似乎没那么直观,但别担心,我们可以轻松地将它封装成我们习惯使用的函数。

替代Math.random()的函数:

我们可以生成一个 32 位无符号整数,然后将其转换为 0 到 1 之间的浮点数。

function secureRandom() {
  //创建一个能容纳一个 32 位无符号整数的数组
  const array = new Uint32Array(1);
  // 填充随机值
  crypto.getRandomValues(array);
  // 将其除以 32 位整数的最大值(2^32-1),得到[0,1)范围的浮点数
  return array[0] / (Math.pow(2, 32) - 1);
}
console.log(secureRandom());// 输出:0.81...(一个密码学安全的随机浮点数)

生成范围内安全随机整数的函数(常用):

function secureRandomInt(min, max) {
  const range = max - min + 1;
  // 创建一个足够大的随机数,以减少模偏差
  const randomValue = new Uint32Array(1);
  crypto.getRandomValues(randomValue);

  return min + (randomValue[0] % range);
}

console.log(secureRandomInt(1, 6));   // 模拟安全的骰子
console.log(secureRandomInt(1000, 9999)); // 生成一个安全的 4 位验证码

Math.random()适用于那些不涉及安全或公平性的应用场景,例如:

  • 生成随机的粒子效果、模拟下雨或下雪;
  • 创作随机的图案和视觉效果;
  • 需要玩家通过分享种子来玩到完全相同的游戏关卡。

当需要真随机时,请选择crypto.getRandomValues(),目前早已兼容各现代浏览器(IE 除外)。

以上关于别再用 Math.random() 了!使用crypto.getRandomValues()安全替代的文章就介绍到这了,更多相关内容请搜索码云笔记以前的文章或继续浏览下面的相关文章,希望大家以后多多支持码云笔记。

「点点赞赏,手留余香」

1

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 admin@mybj123.com 进行投诉反馈,一经查实,立即处理!
重要:如软件存在付费、会员、充值等,均属软件开发者或所属公司行为,与本站无关,网友需自行判断
码云笔记 » 别再用 Math.random() 了!使用crypto.getRandomValues()安全替代

发表回复