伪随机数与真随机数的区别 - 如何区分的整理
· 小村 豪 · 伪随机数, 真随机数, RNG, CSPRNG, 信息安全
讨论随机数的时候,许多本质上相当不同的东西都被用「随机」一词一笔带过,因此话题很容易跑偏。像 Math.random() 这种用计算生成的数列,和从热噪声、时钟抖动这类物理现象中取得的数列,光看外观都会显得差不多散乱。
但在实务上,如果让这个区别一直模糊下去,就容易在下面这些判断上出错:
- 在仿真中想重现结果,但每次跑出来都会有偏差
- 用容易预测的随机数生成密码重置 token
- 只因为通过了统计检验就以为「这就是真随机数」
- 反过来,一听到「伪」就误以为全都不安全
本文尝试以实务上容易判断的方式,整理「什么是伪随机数」「什么是真随机数」「该如何区分」。重点放在不是看输出的外观,而是看生成器的结构。
文中内容以 2026 年 4 月时点可确认的 NIST、IETF、操作系统、编程语言官方资料为依据整理而成。
1. 先下结论(一句话)
虽然有点粗略,但先用实务上比较管用的说法,可以这样讲:
- 伪随机数是从内部状态与算法确定性地生成的数列
- 真随机数是把热噪声、抖动等物理现象当作熵源的数列
- 不过,实务上常用的安全随机数 API,大多并不是直接把物理随机数返回给你,而是用熵源为一个
DRBG / CSPRNG播种后再返回结果 - 因此,光看「外观是否随机」没办法区分。要看的是生成器的结构、种子如何进入、reseed、health test
- 在仿真或重现测试中,伪随机数的可重现性是一项优势
- 在密钥、token、nonce 这类信息安全用途中,原则上要用操作系统或编程语言提供的安全随机数 API
总之,先把下面 3 件事分开来想,比较不容易跑偏:
- 讨论的是「普通的 PRNG」吗
- 讨论的是「密码学用的 PRNG / CSPRNG / DRBG」吗
- 讨论的是「具有物理熵源的 NRBG / TRNG」吗
2. 本文所说的「伪随机数」与「真随机数」
在这个话题里,单纯说「随机数」的范围太宽泛。所以先把定义固定下来。
- 伪随机数(PRNG):根据种子与内部状态,以确定性步骤生成数列。同样条件下会生成相同的数列
- 密码学用伪随机数(CSPRNG / DRBG):虽然也是伪随机数的一种,但强调不可预测性。NIST SP 800-90A 就是在定义这类 deterministic random bit generator
- 真随机数:在日常用语里,通常指的是「真随机数」或「物理随机数」。NIST 术语中较接近的是
NRBG(non-deterministic random bit generator),其说明是「持续参照熵源,在正常情况下具有 full entropy 输出的生成器」
这里的重点是,「伪随机数」并不等于「不安全的随机数」。
例如,线性同余法或简单的 xorshift 这类高速 PRNG,和 CTR_DRBG、HMAC_DRBG 这类 CSPRNG,虽然同样都是确定性的,但在安全意义上差别相当大。
3. 先用一张图整理
3.1. 关系图
先用一张图看看概念之间的相对位置:
flowchart LR
NOISE["物理现象<br/>热噪声、抖动等"] --> ENT["熵源"]
ENT --> SEED["种子 / 重新播种"]
SEED --> DRBG["DRBG / CSPRNG<br/>高速展开随机数"]
DRBG --> API["操作系统 / 库返回的随机数"]
STATE["内部状态 + 数学公式"] --> PRNG["普通的 PRNG"]
PRNG --> OUT["外观类似随机的数列"]
这里的重点是,应用程序拿到的「安全随机数 API」输出,和右侧的「普通 PRNG」、左侧的「原始物理噪声」都有些不同。
多数实现是用左侧的熵源做种子 / 重新播种,再以 DRBG / CSPRNG 高速展开后的数值返回。NIST SP 800-90B 与 800-90C,正是在整理这种「entropy source + deterministic generator」结构的文档。
3.2. 术语最简整理
| 种类 | 用什么生成 | 同样条件下可重现 | 特别要求的是什么 | 适合的用途 |
|---|---|---|---|---|
| 普通的 PRNG | 数学公式与内部状态 | 可以 | 速度、可重现性 | 仿真、游戏、测试 |
| CSPRNG / DRBG | 密码算法 + 种子 | 可以 | 不可预测性 | 密钥、token、nonce、连接 ID |
| 真随机数 / NRBG | 物理熵源 | 基本上不行 | 物理上的不确定性、熵量 | 种子供给、认证设备、需要高审计要求的抽签 |
最简记法是:
- 普通的 PRNG:「可以重现的随机数」
- CSPRNG:「可以重现,但设计成外部难以预测的随机数」
- 真随机数:「从物理现象中提取熵的随机数」
4. 什么是伪随机数
4.1. 一句话说明
伪随机数是在更新内部状态的同时,用计算生成「看起来像随机数的数列」。
只要输入同样的种子、使用同样的算法、取出同样的次数,就会得到同样的数值序列。这乍看像是缺点,但在仿真、测试、调试中反而是很大的优点。
正因为可以重现,「用这个种子能重现 bug」「想把昨天的结果再对比一次」这类用法才能成立。
4.2. 把普通的 PRNG 与 CSPRNG 分开看
这里是最容易被误解的地方。「伪随机数 = 假的 = 不能用」,是不对的。
NIST SP 800-90A 定义的,就是以哈希函数或分组密码为基础的 deterministic random bit generator。也就是说,信息安全用途中使用的随机数,其核心很大一部分也是确定性的生成器。
两者的区别不是单纯的「看起来像不像随机」,而是从攻击者视角看的不可预测性。
- 普通的 PRNG
- 快
- 容易重现
- 内部状态或种子泄露后,容易被预测
- CSPRNG / DRBG
- 也是确定性的
- 但在假设内部状态未知的前提下,设计上要让输出难以被预测
- 信息安全用途下应使用这种
所以光用「是不是伪随机数」判断安全性,几乎一定会踩坑。该看的是「是哪一种伪随机数」。
5. 什么是真随机数
5.1. 一句话说明
真随机数是从热噪声、振荡器的抖动、雪崩噪声、量子现象这类物理上的不确定性中提取熵。
日常中称为「真随机数」或「物理随机数」。在 NIST 术语中较接近的是 NRBG,定位为「持续访问熵源,只要运行正常就能具有 full entropy 输出的生成器」。
5.2. 物理随机数不一定会直接使用
这里也很重要。即使是真随机数,也不一定会把原始测量值直接交给应用程序。
物理源在实务上会存在下面这些难点:
- 存在偏差
- 会受到温度、电源、故障、老化的影响
- 原始输出速率可能不高
- 没有健康检测的话,出故障也很难察觉
因此在 NIST SP 800-90B 中,非常重视熵源的设计原则、min-entropy 的概念、验证测试(validation test)、健康检测(health testing)。从整体实现来看,像 NIST SP 800-90C 那样以「entropy source + DRBG」的方式使用,才是常见做法。
换句话说,「真随机数」不是那种原始的神秘之物,而是连同物理源、评估、监测、后处理一起处理的东西。
6. 到底差在哪里
随机数的区别,光看「看起来是不是随机」并不足以说清楚。至少从下面 4 个角度切入,比较容易看清楚:
6.1. 生成来源
- 伪随机数:算法与内部状态
- 真随机数:物理熵源
这是本质上最大的区别。
6.2. 可重现性
- 伪随机数:同样的种子可以重现
- 真随机数:在同样条件下重新采集,也很难得到相同的数值序列
可重现性在测试中是优点,在抽签中则可能是缺点。
6.3. 可预测性
- 普通的 PRNG:种子或内部状态被获取之后,下一个值相当容易推算出来
- CSPRNG:在内部状态受到保护的前提下,设计成难以提前推算
- 真随机数:只要物理源正常就难以预测,但传感器故障或设计不良就是另一回事
在信息安全领域中,这个角度最重要。比起表面上的分布,更关键的是「能不能猜到下一个值」。
6.4. 速度与应用
- 伪随机数:高速、稳定、容易实现
- 真随机数:需要采集熵并进行监测,速度与实现成本会受限
因此在正式系统中,不是「只用真随机数」或「只用伪随机数」的二选一,而是「以物理熵播种的 CSPRNG」最为实际。
7. 该如何区分
7.1. 原则上光看输出无法区分
最重要的答案就是这一点。仅凭有限数量的输出序列,没办法断定「这就是真随机数」。
理由很简单:随时都可以做出一个能返回和目前观察到的有限长度完全相同序列的确定性程序。极端一点说,把那个序列放进数组或 ROM,依次返回就好了。
因此,不能因为「看起来自然」就说是「真的」。NIST SP 800-22 也明确指出,统计检验最多只是第一步,不能仅靠它来绝对证明生成器的正当性。
反过来说,设计良好的 CSPRNG,光看输出也会让你很难把它和真随机源区分开来。这里的「难以区分」,其实正是设计目标之一。
7.2. 首先要看的是生成器的设计
要区分的时候,与其看输出的外观,不如先确认下面这些项目,会更本质:
- 生成算法是什么
- 是简单的 PRNG,还是 DRBG / CSPRNG
- 种子来自哪里
- 是固定种子、时间、PID 这类
- 还是来自操作系统的熵源
- 是否会重新播种(reseed)
- 只在启动时播种一次就结束了吗
- 运行中是否也会重新注入
- 熵源是否经过验证
- 有没有 min-entropy 的评估
- 有没有健康检测(health test)
- 是否能检测故障
- 使用的是哪个 API
- 是自己写的吗
- 还是操作系统 / 编程语言标准 API
从这些角度来看,多数情况下其实都能分辨:
- 「只要固定种子,每次都生成一样的序列」→ 伪随机数
- 「具有物理熵源、以验证 / 健康检测为前提」→ 带有真随机源的设计
- 「调用的是操作系统的 secure RNG API」→ 大多是「物理熵 + CSPRNG」的混合架构
7.3. 其次,用统计检验找出明显的缺陷
统计检验并非不必要,反而很重要。只是它的作用比较接近「检测缺陷」,而不是「证明」。
典型的观察角度包括:
- 0 与 1 的偏差
- run(连续相同值序列)的偏差
- 周期性
- 相关性
- 近似熵
- 线性复杂度
代表性参考有 NIST SP 800-22,日本则常参照 CRYPTREC 的随机数检验最低组合。它们对于「检查该序列是否有明显偏差或结构」很有用。
但即使通过,也不能说「这就是真随机数」。设计良好的 CSPRNG 也很有可能通过;反过来,物理随机源也可能因为传感器偏差或故障而失败。
检验的定位大致如下:
- 通过:目前还看不出明显缺陷
- 失败:大概率有问题
- 因此它能证明这是真随机数:做不到这一点
7.4. 在信息安全用途中要以攻击者视角来看
在密码重置 token、连接 ID、nonce、密钥生成这类用途中,光问「是真的吗」是不够的。
真正要看的是「攻击者能不能预测下一个值」。
例如:
- 只用当前时间做种子
- 只把 PID 或序列号混进去
- 自己实现却没评估种子的质量
- 把
random系列 API 拿来做信息安全用途
这类做法,光靠「看起来像那么回事」是挡不住的。
日本 IPA 也建议先掌握信息安全相关 API 与现有库,避免轻易自行实现。Python 文档中明确指出,要优先使用 secrets 模块而不是 random。在 Java 中,对应的位置就是 SecureRandom。
结论是:在信息安全里,「是伪随机还是真随机」并不是核心,「有没有使用安全的种子 / 熵与安全的 API」才更重要。
8. 不同用途该用哪种随机数
| 用途 | 适合的选择 | 原因 |
|---|---|---|
| 仿真、蒙特卡洛(Monte Carlo)、游戏逻辑 | 普通的 PRNG | 快、可用种子重现 |
| 测试重现、bug 重现 | 普通的 PRNG | 可以重现相同输入 |
| 密钥、token、nonce、连接 ID | CSPRNG / 操作系统的 secure RNG API | 需要不可预测性 |
| 种子供给、需要高审计与问责的抽签 | 具备物理随机源的设计,或可审计的机制 | 物理熵或记录可追溯性很重要 |
| 一般应用开发中需要「安全的随机数」 | 操作系统 / 编程语言标准的 secure RNG | 比自行实现更不容易出错 |
在实现层面,下面的选法通常比较稳妥:
- Windows 原生:
BCryptGenRandom - .NET:
System.Security.Cryptography.RandomNumberGenerator - Linux:
getrandom() - Python:
secrets - Java:
SecureRandom
Windows 的 BCryptGenRandom,在 Microsoft Learn 文档中说明默认提供程序符合 NIST SP800-90 的 CTR_DRBG。Linux 的 getrandom() 也在文档中说明可用于 cryptographic purposes。.NET 的 RandomNumberGenerator、Python 的 secrets、Java 的 SecureRandom 也都是以密码学用途为前提设计的 API。
9. 常见的误解
9.1. 通过统计检验,就是真随机数
并非如此。它最多能让你说:「目前还看不出明显偏差」。
9.2. 只要是真随机数,就一定安全
并非如此。物理源如果出故障、有偏差,加上实现不当、缺乏健康检测,质量照样会崩掉。
9.3. 伪随机数全都不安全
并非如此。CSPRNG / DRBG 反而是实务上安全随机数 API 的核心。
9.4. 在信息安全用途中,必须直接使用原始物理随机数
不一定。实务上最常见的是「物理熵源 + CSPRNG」的组合。
9.5. 反正 random 或 Math.random() 看起来也很散,就可以拿来做 token
用途不一样。外观上的分布和对攻击者的不可预测性,是两件事。
10. 实务上犹豫时的判断表
犹豫时,按下面的顺序判断会比较快:
- 是否希望能重现同样的结果
- 是 → 普通的 PRNG
- 否 → 往下看
- 被攻击者预测会不会造成问题
- 会 → 操作系统 / 编程语言标准的 secure RNG
- 不会 → 根据质量需求与速度挑选
- 随机数源本身是否需要问责或审计
- 是 → 考虑物理随机源或通过验证的服务
- 是否想自己实现
- 心情可以理解,但随机数很容易做错,原则上先用标准 API
按这个顺序看,比起只在「伪 vs 真」二选一上纠结,方向会快很多。
11. 结语
如果要用最粗略但实务上好用的方式,讲清楚伪随机数与真随机数的区别,大概就是这样:
- 伪随机数是用计算生成的
- 真随机数是从物理现象中提取熵
- 但实务上的安全随机数 API,主角是介于两者之间的「entropy source + CSPRNG」
也就是说,该看的不是「外观」,而是「结构」。
- 无法只看输出就断定是否为真随机数
- 统计检验在检测缺陷上有用,但不是证明
- 信息安全中真正的战场是「能不能被预测」
- 需要可重现性就用 PRNG,需要不可预测性就用操作系统 / 编程语言标准的 secure RNG
沿着这条思路,就可以跳出「伪随机数是不是假货」这种粗糙的对立。
12. 参考资料
-
NIST SP 800-90A Rev. 1: Recommendation for Random Number Generation Using Deterministic Random Bit Generators deterministic random bit generator 的基础文档。
-
NIST SP 800-90B: Recommendation for the Entropy Sources Used for Random Bit Generation 整理熵源、验证、健康检测的概念。
-
NIST SP 800-90C: Recommendation for Random Bit Generator (RBG) Constructions 整理「entropy source + DRBG」的结构。
-
NIST SP 800-22 Rev. 1a: A Statistical Test Suite for Random and Pseudorandom Number Generators for Cryptographic Applications 说明统计检验的定位。检验是第一步,不等于证明,这一点很重要。
-
NIST Glossary: Non-deterministic Random Bit Generator (NRBG) 确认接近「true random」的 NIST 术语定义。
-
RFC 4086: Randomness Requirements for Security 整理信息安全用途中随机数与熵源的注意事项。
-
Microsoft Learn: BCryptGenRandom function 说明 Windows 的 secure RNG API 以及默认提供程序的
CTR_DRBG。 -
Linux man page: getrandom(2) 在 Linux 上可用于
cryptographic purposes的随机数 API。 -
Microsoft Learn: RandomNumberGenerator 类 .NET 上具备密码学强度的 RNG API。
-
Python 文档:secrets — Generate secure random numbers for managing secrets Python 中处理信息安全用随机数的基础。
-
Oracle Java Documentation: SecureRandom 整理 Java 的 secure RNG 与种子 / 熵的概念。
-
IPA: 第3章 3.不易被破解的密码技术与伪随机数的使用 以日文整理种子的重要性、检验、API 使用注意事项。
相关文章
共享相同标签的最新文章。可以围绕相近的主题进一步加深理解。
Windows 应用程序不要把敏感信息以明文存进配置文件的最佳实践
本文整理 Windows 桌面应用保存连接凭证或 API Token 时的实务做法,说明为什么 DPAPI 与 ProtectedData 比明文或自制加密更能切断「文件外泄即等于敏感信息外泄」这条链条,并对比 CurrentUser 与 LocalMachine 的适用场...
Windows的效率模式是什么 - Windows 11绿色叶子图标代表什么,以及如何关闭
整理 Windows 11 任务管理器中绿色叶子图标与效率模式的真正含义,以及它如何通过降低优先级与 EcoQoS 平衡前台响应、电池与散热。同时说明逐一进程的关闭步骤、灰色选项的处理,以及和 Microsoft Edge 节能功能的差异,以及性能比较时必须对齐的条件。
Windows 什么时候需要管理员权限 - UAC、保护区域与设计上的辨别方式
从边界与存储位置的角度,整理 Windows 什么时候真正需要管理员权限:UAC、保护区域、HKLM、服务、驱动、防火墙。同时说明 per-user 与 per-machine 的差异,以及把管理员处理拆成独立 EXE、服务或任务的设计取舍,帮读者判断该不该提升权限。
在 Windows 环境下减少 Codex 乱码事故的最佳实践 - 先把『指示方式』钉住,再谈环境整备
本文整理在 Windows 上让 Codex 安全处理日文文件的指示原则:读文件前先确认 encoding 与 BOM,疑似乱码禁止臆测保存,现有文件维持原状,仅新建采用 UTF-8,并在写入后重新读取代表性日文行验证,把规则沉淀进 AGENTS.md 以减少事故。
Windows Forms、WPF、WinUI 该怎么选 - 新建项目、存量资产、发布、UI 表现力判断表
从存量资产的规模、界面是表单为主还是需要表现力、现代 Windows UI 是否是产品刚需、发布与运维怎么落地这四个角度,整理 WinForms、WPF、WinUI 该怎么选的判断表,并提醒只想用 Windows App SDK 不必全面迁移到 WinUI。
常见问题
汇总了咨询这一主题时常见的问题。
- 伪随机数是什么?
- 伪随机数(PRNG)是根据种子(seed)与内部状态,以确定性步骤通过计算生成的数列。只要输入同样的种子、使用同样的算法、取出同样的次数,就会得到同样的数值序列。这种可重现性乍看像是缺点,但在仿真、测试、调试中反而是很大的优点,例如「用这个种子能重现这个 bug」这种用法才能成立。要注意的是,伪随机数并不等于不安全的随机数,CSPRNG / DRBG 也是伪随机数的一种。
- 伪随机数和真随机数的区别在哪里?
- 本质上最大的区别在于生成来源:伪随机数来自算法与内部状态,真随机数则把热噪声、振荡器抖动这类物理现象当作熵源。在可重现性上,伪随机数用同样的种子可以重现,真随机数在同样条件下重新采集也很难得到相同序列。在速度与应用上,伪随机数高速、稳定、容易实现,真随机数需要采集熵并进行监测,速度与实现成本会受限。
- 可以只看输出就判断是不是真随机数吗?
- 原则上做不到。仅凭有限数量的输出序列,没办法断定这是真随机数,因为随时都可以做出一个能返回完全相同序列的确定性程序。NIST SP 800-22 也明确指出,统计检验最多只是第一步,不能仅靠它来绝对证明生成器的正当性。要区分时,应该看的是生成器的结构:生成算法是什么、种子来自哪里、是否会重新播种(reseed)、熵源有没有健康检测(health test)、使用的是哪个 API。
- 信息安全用途(token、密钥等)该用哪种随机数?
- 在密钥、token、nonce、连接 ID 这类信息安全用途中,原则上要用操作系统或编程语言提供的安全随机数 API,例如 Windows 原生的 BCryptGenRandom、.NET 的 RandomNumberGenerator、Linux 的 getrandom()、Python 的 secrets、Java 的 SecureRandom。这些大多是以物理熵源为种子驱动一个 CSPRNG / DRBG 的混合架构。关键不在于「是伪随机还是真随机」,而在于攻击者能不能预测下一个值,所以不要把 random 系列 API 拿来做信息安全用途,也不要轻易自行实现。
作者简介
本文作者的个人简介页面。
Go Komura
小村软件有限公司 代表
以 Windows 软件开发、技术咨询与故障排查为中心,擅长难以复现的故障调查,以及既有资产仍在运行的项目。