Math.random vs crypto.getRandomValues

对比 Math.random 和 crypto.getRandomValues 的安全性、适用场景与使用方式。

#type / synthesis #status / evergreen #resource / javascript #tech / dev / frontend #platform / browser #tech / security

[!info] related notes

Math.random vs crypto.getRandomValues

为什么要把这两个放在一起理解

两者都是 JavaScript 中生成随机数的方式,但安全等级完全不同。在需要安全性的场景(密码、令牌、密钥)中用错,会导致严重的安全漏洞。

核心对比

维度Math.random()crypto.getRandomValues()
算法伪随机(xorshift128+ 等)密码学安全(CSPRNG)
随机源纯算法,种子可推算操作系统熵池(硬件噪声等)
可预测性收集足够输出可推算后续值不可推算
速度更快稍慢(实际差异可忽略)
全局可用所有 JS 环境浏览器 + Node.js 19+

使用边界

Math.random() 的场景

  • 动画效果的随机抖动
  • 游戏中的非关键随机(如粒子特效)
  • 非安全的 UI 随机化(如随机背景色)

必须用 crypto.getRandomValues() 的场景

  • 生成用户密码
  • 生成 CSRF Token
  • 生成 API Key / Secret
  • 生成 Session ID
  • 任何需要防止预测的安全场景

常见错误

❌ 用 Math.random 生成密码

// 危险!密码可被预测
function generatePassword(length) {
  const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
  let password = '';
  for (let i = 0; i < length; i++) {
    password += chars[Math.floor(Math.random() * chars.length)];
  }
  return password;
}

❌ 用 sort + Math.random 洗牌

// 错误!分布不均匀
const shuffled = arr.sort(() => Math.random() - 0.5);

✅ 安全的实现

function getSecureRandomInt(max: number): number {
  const array = new Uint32Array(1);
  crypto.getRandomValues(array);
  return array[0] % max;
}

function secureShuffle(array: string[]): string[] {
  const result = [...array];
  for (let i = result.length - 1; i > 0; i--) {
    const j = getSecureRandomInt(i + 1);
    [result[i], result[j]] = [result[j], result[i]];
  }
  return result;
}

学习顺序建议

  1. 先理解 Math.random 为什么不安全(伪随机原理)
  2. 再学 crypto.getRandomValues 的用法和兼容性
  3. 最后掌握 Fisher-Yates 算法 + 安全随机数的组合
创建于 2026/3/30 更新于 2026/5/27