开发者工具 · UUID 生成器
Math.random 与 crypto.getRandomValues:每个生成器的工作原理
· 工作原理
uuid 密码学 浏览器 API
两者都返回看起来随机的数字,但其中一个是小型确定性状态机,另一个由操作系统提供。以下是两者的幕后作用以及为什么 UUID 必须使用第二个。
从 Math.random 构建 UUID 的论坛片段 — 为什么它看起来不错并通过了每个临时测试
论坛答案提供了一个八行的快速 UUID 工厂:从 Math.random 滚动值并将它们格式化为 8-4-4-4-12 布局。代码看起来不错并且通过了每一个临时测试。每个标识符看起来都不同,并且简短的示例没有显示明显的视觉模式。这不是安全敏感标识符所需的属性。 JavaScript 将 Math.random 指定为伪随机源,但不需要密码学抵抗预测。它适合的工作包括模拟、游戏和洗牌。一旦标识符可以影响访问、对象发现或其他对抗性决策,外观就不再是证据。发电机的书面合同比一页看似合理的输出更重要。
Inside Math.random — 具有固定内部状态的种子伪随机算法,专为速度和统计传播而不是保密而设计
由于 Math.random 未指定为加密生成器,因此不得将其输出视为未来值对观察者隐藏的证据。 crypto.getRandomValues 有一个不同的平台契约:它用加密强值填充整数类型数组。 Web 加密规范将确切的生成器留给用户代理,因此应用程序代码不应声明特定的算法、种子大小或熵设备。 ToolAcre 仅需要受支持的边界:浏览器提供安全随机字节,JavaScript 接收填充的 Uint8Array,并且 UUID 代码设置版本和变体字段。该语句在内部实现不同的浏览器之间既有用又可移植。
为什么观察输出可以揭示状态 - 小状态如何意味着一系列值可以让某人预测下一个值
应用程序代码从 getRandomValues 接收加密强值,而不是实现或公开 JavaScript PRNG 状态。安全差异在实际系统中显现出来。从 Math.random 构建的标识符在预测会产生后果的情况下是不合适的,因为能够读取网络(或任何先前 UUID 可见的系统)的攻击者可以预测下一个。来自 crypto.getRandomValues 的 v4 UUID 本身并不是身份验证令牌(您仍然需要过期、散列、速率限制),但生成器旨在抵抗预测。如果不存在安全源,ToolAcre 将拒绝生成标识符,而不是默默地降级为可预测的公式。 Math.random 在主要引擎中附带了微妙的分发错误。输出序列可能看起来有所不同,但没有提供秘密承载角色所需的对抗性不可预测性。
crypto.getRandomValues 内部 - 浏览器询问操作系统的 CSPRNG,它混合了硬件和系统熵,并且被设计为不可预测
引擎特定的算法及其统计行为可能会改变;无论是目视检查还是随机分布测试都无法将 Math.random 升级为加密源。碰撞计算还假设来自指定空间的独立输出。如果生成器重复状态、种子错误或被确定性固定装置替换,则该假设失败,并且该公式不再描述实现。这两个 API 都可以生成看起来同样不规则的字符串。威胁模型将它们分开:必须抵抗预测的值使用 crypto.getRandomValues,而模拟和非对抗性洗牌可能使用 Math.random。选择是根据预测的结果,而不是根据标点符号或样本中的明显变化。
工作示例 - 使用每种方法生成相同数量的标识符并比较观察者可以推断出的内容
ToolAcre UUID 生成器专门使用 crypto.getRandomValues;它从不使用 Math.random,因为可预测的 UUID 的成本总是高于稍慢的生成器的成本。加密差异可以通过威胁模型来衡量。想要伪造 UUID 的攻击者必须直接猜测标识符或破坏随机数生成器。直接猜测不是本文量化的比较;支持的结论是 Web Crypto 旨在实现加密随机性,而 Math.random 则不是。 CSPRNG 和 Math.random 公开了不同的合约:前者是为安全敏感的随机性而设计的,而后者则没有这样的承诺。使用 Math.random 作为标识符的系统已经失去了加密属性;现在的安全性取决于对生成的 UUID 序列进行保密。即使有一个 UUID 泄漏,整个下一代都会受到损害。
历史性的分发错误 - 提醒引擎已经提供了具有明显不均匀输出的 Math.random 实现,并进行了定性描述
如果应用程序将 UUID 存储在日志、数据库或版本控制历史记录中,则泄漏几乎是不可避免的。 ToolAcre 库强制使用 crypto.getRandomValues,并在安全上下文(HTTPS 或 localhost)不可用时拒绝生成 UUID。这种设计决策可以防止静默回退到困扰许多手动实现的 Math.random。在 Node.js 中,该库使用 crypto 模块;在浏览器中,它使用 Web Crypto API。两种受支持的路径都要求平台具有加密的强随机性。该实现没有提出任何性能要求,因为引擎、设备和工作负载决定了时序;安全合约是标识符的决定性属性。为什么行业标准决定采用 crypto.getRandomValues 是 UUID 滥用的简短历史。早期系统使用系统时间、网络接口和硬件时钟来生成标识符。
这不包括任何模拟生成器的统计质量,这是与不可预测性不同的问题
基于时间、基于节点和随机 UUID 版本解决不同的分配问题;不应将其呈现为对每个早期设计的线性修复。对于版本 4,RFC 9562 定义了随机字段并单独讨论了不可猜测性。因此,从 Math.random 的迁移会改变新生成的值的质量,而不会更改文本 UUID 形状。现有标识符仍然是数据库密钥;重新生成它们会破坏引用。新值可以立即使用 Web Crypto,而授权必须继续将每个旧的或新的 UUID 视为标识符而不是权限证明。记录截止时间,以便事件响应人员知道哪个发电机产生了每个种群。
要点:根据威胁而不是外观来选择生成器 — ToolAcre UUID 生成器专门使用 CSPRNG,从不使用 Math.random()
验证应区分旧 ID(不适合保密)和新 ID(CSPRNG 支持)。文档应记录这种转变。 ToolAcre 生成器仅生成 crypto.getRandomValues UUID;它不会尝试验证或重新生成来自其他来源的标识符。 ToolAcre 生成器通过拒绝降级到较弱的随机源来展示最佳实践。如果 crypto.getRandomValues 不可用,该工具会报告错误,而不是默默地使用 Math.random。这一设计原则适用于任何安全关键系统:大声失败而不是在安全保障较弱的情况下悄然成功。看到“UUID 生成失败:加密 API 不可用”的开发人员必须解决根本问题(升级到 HTTPS、修复安全上下文或提供适当的后备)。默默接收从 Math.random 构建的 UUID 的开发人员并没有迹象表明系统已受到损害。 ToolAcre 库优先考虑诚实而不是方便。