qinghuan
← 回到知识探索

计算机趣闻 / 常见误区

每次数字都不同,就能当安全随机数吗?

模拟实验需要可重复,验证码和令牌则需要难预测;外观看不出这个差别。

展开本文目录
  1. 能重放的随机过程,有时正是我们想要的
  2. 安全随机关注的是别人能否猜下一步
  3. 生成器选对了,取余也可能偏心
  4. 让成熟接口负责范围与随机来源
  5. 记住这三点
  6. 别把例子用过头
  7. 自己试一小步
  8. 查原始资料
  9. 找一份资料继续练
开始前,会这些就够了
  • 知道除法余数的含义
遇到不熟悉的词,先看这 1 个解释
安全随机数
安全随机数强调别人难以预测接下来的结果,适合生成保密凭据等用途。它通常由系统提供的可靠随机来源产生,不能只凭数字看起来杂乱或没有重复来判断安全。
打开完整术语小抄 ↗

一串数字看起来没有规律,连续运行几次也不相同,很容易让人觉得它足够随机。但动画里随机挑一种颜色,与生成一个别人不能猜到的重置令牌,对随机数的要求并不一样。差别需要看生成方式和用途,不能靠盯着几行输出判断。

能重放的随机过程,有时正是我们想要的

普通伪随机生成器根据内部状态计算后续数字,种子用于初始化状态。在兼容的算法与相同调用顺序下,使用同一种子可以重现同一序列。这个特性对模拟和测试很有用:一次随机输入触发了错误,保存必要条件后就有机会重新得到那组输入。

例如 Python 默认 random 适合建模和模拟,官方明确提醒它不适合密码学用途。重现也不只靠记一个种子:库版本、算法和调用次数都可能影响结果。若一段代码额外抽取了一个数,后面的序列位置就变了,不能把所有差异都归咎于种子失效。

安全随机关注的是别人能否猜下一步

安全场景里,生成的值可能会被别人看到一部分,程序仍需要让后续值难以预测。应使用语言或操作系统提供的密码学安全随机接口,例如 Python 的 secrets。安全生成器也可能使用伪随机算法;“伪”不直接等于不安全,关键在设计、初始随机来源和正确使用。

同样,“这次没重复”不是安全证明。按顺序发号也可以保证很长时间不重复,却很容易猜到下一号。反过来,安全随机结果也不是绝对不会重复。数据库要求唯一编号时,仍要考虑冲突处理;需要保密凭据时,唯一性本身又不能替代难预测性。

生成器选对了,取余也可能偏心

假设一个小模型能等概率产生零到十五,共十六个数。为了选六种颜色,我们直接对六取余。问题是十六不能被六整除:有些余数有三个原数对应,有些只有两个。即使原始数字完全公平,后面的映射也会让某些颜色更常出现。

下面枚举全部十六种可能,只统计映射次数,不调用任何随机生成器。第一行显示直接取余的分布,第二行只统计零到十一这一整段后再取余。实际随机抽样若遇到其余值,需要重新抽取;这里展示的是计数理由,不是一套生产随机数实现。

小实验 · javascript
const direct = Array(6).fill(0);
const accepted = Array(6).fill(0);
for (let x = 0; x < 16; x++) {
  direct[x % 6]++;
  if (x < 12) accepted[x % 6]++;
}
console.log(direct.join(" "));
console.log(accepted.join(" "));

怎样运行:在浏览器控制台或 Node.js 中运行。这是全部可能值的枚举,不是随机抽样或安全性测试。

运行后对照结果
3 3 3 3 2 2
2 2 2 2 2 2

让成熟接口负责范围与随机来源

实际项目应优先使用已经处理好范围选择的接口。Node.js 的 crypto.randomInt 明确说明会避免取余偏差,Python secrets 也提供指定上限内取整数的功能。读文档时要特别注意上限是否包含,避免原本想选六项,却意外产生第七个索引。

生成令牌还需要足够的随机字节数,以及合适的保存、过期和使用规则,不能用一个安全函数包办所有问题。把六个随机字节转成十二个十六进制字符,只是换了显示方式,并没有把随机信息翻倍。先把数量与用途写清楚,再选择接口,比把字符串拼得很长更可靠。

记住这三点

  • 可重复适合模拟和调试,难预测适合保密凭据,二者需求不同。
  • 不重复、分布看似均匀和密码学安全,不是同一件事。
  • 范围映射可能引入偏差,优先使用提供所需范围的成熟接口。

别把例子用过头

  • 这段枚举只解释取余偏差,不能用来证明某个生成器安全。
  • 安全随机也不提供绝对唯一保证。
  • 编码成更长字符串不会增加原始随机字节携带的信息量。

自己试一小步

从零到三十一均匀取数,怎样公平选择五个选项?

  1. 先列出直接对五取余时,各个结果分别对应几个输入。
  2. 寻找可以完整分成五组的保留范围,并写下范围外如何处理。
  3. 分别为可重放的模拟和需要难预测值的场景,选择合适的标准库类别。

做到这些,就算完成

  • 计数覆盖全部输入,没有漏掉零或弄错上限。
  • 能解释筛除后为何需要重新抽取。
  • 没有把自写的教学映射当作登录系统的随机实现。

查原始资料

想确认一个细节,先看这份资料对应的部分,不必从头读完所有文档。

找一份资料继续练

先选一项,按下面的范围继续学;不必从头读完整门课程。