授权与合规声明
本文全部操作对象均为自建隔离靶场(本机容器或隔离虚拟机),涉及安全测试的环节必须以取得合法授权为前提。未经授权的渗透测试违反《中华人民共和国网络安全法》与《刑法》相关条款,须承担相应法律责任。本文只讲环境配置、版本对照与靶场隔离,不含任何攻击步骤、利用载荷与绕过手法,请勿将文中环境指向任何非自有系统。

一、同一句"取个随机数",其实是两种要求

1.1 两种脚本,那句代码长得一模一样

写脚本的人几乎都会说出同一句话:这里取个随机数。可是这句话落到两种场合,指向的是两件并不相同的事。

  • 做模拟、抽样、随机取值、洗牌、给测试造一批样例数据——这些场合要的是"结果分布均匀、看起来乱、没有肉眼能看出的规律"。
  • 生成 token、密钥、会话标识、重置链接里那一串字符——这些场合要的不是"看起来乱",而是"别人猜不到"。

前者要面对的是"看数据的人",后者要面对的是"想把那串东西猜出来的人"。观众不同,尺子也不同。

1.2 两把尺子,不要混用

两种场合并排放在一张表里,"同一个词、两个标准"立刻显形。

场合真正的要求谁在盯着它
模拟、抽样、测试样例、洗牌分布均匀、看起来乱你自己的分析过程
token、密钥、会话标识、重置链接猜不到任何想知道它的人

看第二行最后那一格:对手不是"看数据的人",而是"想把整串东西搜出来的人"。要求于是从"看起来乱"升级成"猜不到"——两者并不等价,这就是本文要讲的全部。

1.3 本文只做一件事

本文只回答一个问题:当你在脚本里写下"取个随机数"时,怎么判断这里要的是哪一种,以及该用什么去取。

三件事先说清楚:

  • 本文不写任何"怎么去猜、怎么去试出某个随机数或那串标识"的思路或步骤。
  • 本文谈的是随机性本身;哈希用于完整性、内容寻址的题目属于另一条轴,本文不复述它的定义(第二章会用一句话把这条界划出来)。
  • 本文不涉及编码,也就是字符与字节之间怎么互相转换那一类问题。

本章可以带走的一句:脚本里那句"取个随机数"其实有两种要求,一种是"看起来乱",一种是"猜不到",判断自己落在哪一边,是所有选择的起点。

二、“看起来乱"不等于"猜不到”

2.1 标准原文里那句最直接的判断

随机性这件事,国际上有一份权威文本可直接拿来当尺子——RFC 4086《Randomness Requirements for Security》,它同时是 BCP 106。它第一节里有一句判断,几乎就是照着"看起来乱就够了"说的:

This can easily fail if pseudo-random data is used that meets only traditional statistical tests for randomness, or that is based on limited-range sources such as clocks. Sometimes such pseudo-random quantities can be guessed by an adversary searching through an embarrassingly small space of possibilities.

——如果用的是只通过了传统统计检验的伪随机数据,或者来自像时钟这样范围有限的源,这件事很容易失败;这类伪随机量,有时会被对手在一个小得令人尴尬的可能性空间里搜出来。

要害有二。第一,"能通过统计检验"和"猜不到"是两回事:统计检验只问分布像不像随机,管不了"来源是否容易被复制"。第二,"范围有限的源"是硬伤:时钟能取的值就那么些,拿它当源头,产出就天生带着这个上限。

2.2 官方给这件事起了个名字:“伪安全”

紧接着还有一句更狠的判断,出自同一份文本的摘要:

The use of pseudo-random processes to generate secret quantities can result in pseudo-security. A sophisticated attacker may find it easier to reproduce the environment that produced the secret quantities and to search the resulting small set of possibilities than to locate the quantities in the whole of the potential number space.

——用伪随机过程去生成"用于保密的量",得到的结果可能是**“伪安全”。一个老练的对手,把产生这些量时的环境复现出来、再在由此得到的小集合里搜,可能比在完整的可能性空间里去找还要容易**。

这句里藏着一个反直觉的点:对手不一定要"更聪明",他只要"能把环境摆回原样"。一旦做到,你要防的完整空间就塌缩成了一个小集合。这就是"伪随机"与"密码学随机"分家之处。

2.3 为什么标准把它抬到"核心"的高度

RFC 4086 在第一节里还写了两句,把这件事的位置摆得很高:

At the heart of all cryptographic systems is the generation of secret, unguessable (i.e., random) numbers.

The lack of generally available facilities for generating such random numbers (that is, the lack of general availability of truly unpredictable sources) forms an open wound in the design of cryptographic software.

第一句说:一切密码系统的核心,是生成"保密的、猜不到的"数字。 第二句说:缺少"能普遍用上的、真正不可预测的源",是密码学软件设计里的一处"开放伤口"。

注意"真正不可预测"——它和"统计上像随机"不是一个要求。第一句那个括号也值得多看:官方把"猜不到的"直接注成了"random",在要求"猜不到"的语境里,这个词的分量比日常用法重得多。

2.4 一条必须划清的界

这里要划一条界:本文谈的是"随机性够不够猜不到",而"校验和与签名"“镜像标签与摘要"那两篇谈的是"哈希用于完整性校验与内容寻址”,是另一条轴上的事,本文不复述哈希的定义,也不谈碰撞与签名。

本章可以带走的一句:判断一个随机源合不合格,看的不是"它像不像随机",而是"产生它的那套环境和范围,别人能不能复现"。

三、种子:伪随机的命门

3.1 官方那个"8 位种子配 128 位密钥"的例子

伪随机生成器的输出完全由一个初始值决定,这个初始值叫种子。种子有多薄,产出就有多薄。RFC 4086 第三节举了一个例子,把这件事说得非常直白:

consider a cryptographic system that uses 128-bit keys. If these keys are derived using a fixed pseudo-random number generator that is seeded with an 8-bit seed, then an adversary needs to search through only 256 keys (by running the pseudo-random number generator with every possible seed), not 2^128 keys as may at first appear to be the case. Only 8 bits of “information” are in these 128-bit keys.

——设想一个用 128 位密钥的密码系统。如果这些密钥是用一个固定的伪随机生成器、以 8 位种子导出来的,那么对手只需要搜 256 把密钥(把伪随机生成器按每一种可能的种子跑一遍),而不是它乍看之下的 2^128 把。这 128 位密钥里,只有 8 位"信息"。

这个例子值得逐字读:它把一句容易被忽略的话摆上台面——密钥的长度,不等于密钥里"信息"的量。 128 位是"格子有多少",8 位是"真正填进去的不确定性有多少",后者才决定这道题难不难。

说明:这里的 256 与 2^128 是官方原文给出的对照。本文只引用这一处,不另外做任何数值推算。

3.2 本机实测:同一种子,两次输出逐位一致

理论讲完,回到自己机器上跑一遍,会更直观。下面这段脚本在本机跑过,输出是什么样,原样放在代码块后面。

2026-10-14 本机实测

import random, secrets

def three_floats():
    random.seed(2026)                 # 同一个种子
    return [round(random.random(), 6) for _ in range(3)]

print("第一次:", three_floats())
print("第二次:", three_floats())

print("token 第一次:", secrets.token_hex(8))
print("token 第二次:", secrets.token_hex(8))

本机(Python 3.13.12)输出:两次的 random.random() 序列完全相同(0.11912 / 0.502516 / 0.511823),而 secrets.token_hex(8) 两次结果不同。

同一台机器、同一份脚本,只因种子被固定成 2026,那串"看起来乱"的小数就每次都一模一样。伪随机的输出不是"凭空乱",它是从一个确定起点按确定规则"长"出来的:起点不变,长出来的就不变。

3.3 "可复现"是特性,也是命门

必须说清:可复现本身不是缺陷,它是伪随机生成器的设计目标。 做模拟、跑实验、给别人复现结果,都需要"同种子出同一串数"。

问题出在用错场合。一旦把这套"可复现"的东西用在"要求猜不到"的地方,优点立刻翻面成命门:只要种子被别人拿到或猜到,整串结果就能被完整重放。 于是全部安全强度,就退回到"种子有多难猜"这一件事上——而种子从哪来,正是下一章的内容。

本章可以带走的一句:伪随机的输出完全由种子决定,"可复现"在模拟里是优点、在要求猜不到的场合是命门,所以真正要盯住的是种子的来源。

四、系统的熵源在哪里

既然种子决定一切,那么"种子该从哪来",就成了整件事的枢纽。答案是:从操作系统提供的熵源来。这套东西是分层的,从内核一直到你手里那个函数,一共有几站。

4.1 内核那一侧:一个随机设备

在本机(macOS)的 man 4 random 里,对随机设备的定性是这么写的:

The random device produces uniformly distributed random byte values of potentially high quality.

——random 设备产出均匀分布、质量可能很高的随机字节。这是整条链子的最底端,也是"真正的不可预测"通常落脚的地方。

4.2 系统调用那一侧:getentropy(2)

同一份手册接着指出,同样的随机数据还有另一个入口——系统调用:

The same random data is also available from getentropy(2). Using the getentropy(2) system call interface will provide resiliency to file descriptor exhaustion, chroot, or sandboxing which can make /dev/random unavailable.

——同样的随机数据,也能通过 getentropy(2) 拿到。官方给的理由是:走系统调用这条接口,对"文件描述符耗尽、chroot、沙箱"这几类会让 /dev/random 变得不可用的情况更有韧性。

这句话点出一个易被忽略的现实:“设备文件存在"和"我的程序总能打开它”,是两件事。 受限环境里直接读设备文件可能走不通,而系统调用接口绕开了这个依赖。

4.3 用户态那一侧:arc4random(3)

再往上一层,手册给了第三个名字:

the arc4random(3) API provides a fast userspace random number generator built on the random data source and is preferred over directly accessing the system’s random device.

——arc4random(3) 提供了一个建立在 random 数据源之上的、快速用户态随机数生成器,并且比起直接去访问系统的随机设备,官方更推荐用它。

三层结构到这里就清楚了:内核随机设备是源,系统调用是一层稳定入口,用户态 API 又是一层更省心的封装。 越往上,越不用操心"设备能不能打开、读到的够不够"。

4.4 两个设备名与 Fortuna

在 macOS 上,/dev/random 与 /dev/urandom 这两个名字都是存在的。手册对它们的关系有一段话,但它同时牵出一个必须小心的地方:

/dev/urandom is a compatibility nod to Linux. On Linux, /dev/urandom will produce lower quality output if the entropy pool drains, while /dev/random will prefer to block and wait for additional entropy to be collected. With Fortuna, this choice and distinction is not necessary, and the two devices behave identically. You may use either.

这段话有前半句和后半句。后半句讲的是这份手册描述的系统本身:它用 Fortuna 算法,所以那种"选择与区分"没有必要,两个设备行为一致,用哪个都行。前半句"On Linux, …"那一段,是这份 Darwin 手册里描述 Linux 的段落。

这里必须把边界写清楚:截至 2026-10-14,本文不据此为 Linux 侧 /dev/random 与 /dev/urandom 的当前实现下任何结论。 一份手册顺带描述另一个系统的段落,不能当作那个系统现状的依据。

本机的事实可以照实看一眼:

2026-10-14 本机实测

ls -l /dev/random /dev/urandom

本机输出显示,两个名字都指向字符设备(属性以 c 开头,属主为 root wheel)。再看它们背后的算法:

The random device implements the Fortuna pseudo random number generator algorithm and maintains its entropy pool.

——随机设备实现了 Fortuna 伪随机数生成算法,并维护着自己的熵池。所以这里说的"设备",本质上是"一个持续吸收熵、再按算法吐出字节的生成器",而不是一台能测出"真正的物理随机"的仪器。

至于直接调 getentropy(2) 长什么样,下面只给一个形状(本机没有编译运行过其中任何一行):

⚠️ 代码待验证

/* 形状示意:不对应任何真实程序 */
#include <unistd.h>
unsigned char buf[32];
getentropy(buf, sizeof(buf));   /* 从系统熵源取随机字节 */

4.5 一条从源到你手里的链子

把这一章串起来,是一条清晰的链子:

内核熵源(随机设备 / Fortuna)→ 系统调用接口(getentropy(2))→ 用户态 API(arc4random(3))→ 你调用的那个库函数。

你在脚本里写下的那一行站在链子最右端。要判断它靠不靠得住,就往左看:它接到的是"系统的熵源",还是"一个自己造的、种子薄薄的伪随机生成器"。 这正是下一章要讲的。

本章可以带走的一句:要求"猜不到"的随机,最终必须落到操作系统提供的熵源上;内核设备、系统调用、用户态 API 是同一件事的三层入口,越往上越省心。

五、库函数怎么选

链子的最右端,就是平时随手调用的那些库函数。以 Python 为例,官方文档对两个模块各自说了什么,几乎不用翻译就能看懂。

5.1 secrets 的定位:为"保密"而生

Python 官方 secrets 文档的开头是这么写的:

The secrets module is used for generating cryptographically strong random numbers suitable for managing data such as passwords, account authentication, security tokens, and related secrets.

——secrets 模块用来生成密码学强度的随机数,适合处理口令、账号认证、安全 token 以及相关的密钥类数据。紧接着那句,才是这份文档里最该被记住的:

In particular, secrets should be used in preference to the default pseudo-random number generator in the random module, which is designed for modelling and simulation, not security or cryptography.

——secrets 应当优先于 random 模块里的那个默认伪随机生成器被使用,因为后者是为建模与仿真设计的,不是为安全或密码学设计的。

文档还补了一句它的底气从哪来:

The secrets module provides access to the most secure source of randomness that your operating system provides.

——secrets 提供的是你的操作系统所能提供的最安全的随机源。它接到链子的哪里就很清楚了:直接踩在操作系统的熵源上。

5.2 random 的官方警告:它自己承认不适合

random 模块自己怎么说?它的文档里,警告写得很直接:

The pseudo-random generators of this module should not be used for security purposes. For security or cryptographic uses, see the secrets module.

——这个模块里的伪随机生成器不应当被用于安全目的;用于安全或密码学时,请见 secrets 模块。

模块概述里还有一句更彻底:

However, being completely deterministic, it is not suitable for all purposes, and is completely unsuitable for cryptographic purposes.

——它是完全确定性的,因此并非对所有用途都合适,并且完全不适合密码学用途。同一个模块里的 randbytes 条目下也留了一句:

This method should not be used for generating security tokens. Use secrets.token_bytes() instead.

——不应当用这个方法去生成安全 token,应当改用 secrets.token_bytes()。

把这几句放在一起,结论不用自己下:"做模拟的"那个模块,自己就写了不接"要求猜不到"的活。

5.3 该取多长:官方给的口径

选对模块,接着是"取多少"。secrets 文档给了一段关于篇幅的建议,里面既有结论,也有这个结论的时间点:

To be secure against brute-force attacks, tokens need to have sufficient randomness. Unfortunately, what is considered sufficient will necessarily increase as computers get more powerful and able to make more guesses in a shorter period. As of 2015, it is believed that 32 bytes (256 bits) of randomness is sufficient for the typical use-case expected for the secrets module.

——token 要有足够的随机性;而"够"的标准必然会随着算力增长而水涨船高。文档给的时间锚点是 As of 2015(截至 2015 年):**32 字节(256 位)**的随机性,足以覆盖 secrets 模块的典型用例。

最该记的不是"32 字节",而是前面那句"标准会随着算力增长而提高"——所以文档标了时间点,而不是当成永久常数。本机实测也显示,secrets.DEFAULT_ENTROPY 的值是 32(字节),正是 token_* 系列不指定长度时的默认用量。

5.4 一句话的选择原则

把这一章收成一张对照表:

你要做的事该用哪一类判断依据(官方口径)
模拟、抽样、造样例、洗牌伪随机生成器(如 random 的默认生成器)可复现、快、为建模与仿真设计
token、密钥、会话标识、重置链接密码学随机源(如 secrets)文档明写"应当优先"、“最安全的随机源”

原则就一句:先问这个值要不要"猜不到",要,就走密码学随机源那一列;不要,才轮到伪随机生成器。

配套资料:把"两种尺子怎么分"“种子为什么是命门”“系统的熵源三层入口”"库函数怎么选"压成一页对照卡,放在资料包里,扫码即可获取:

配套资料获取

本章可以带走的一句:选库函数之前先问"要不要猜不到"——要,就用密码学随机源(secrets 一类);random 的官方文档自己写了它只做建模与仿真。

六、落到 UUID:为什么 v4 要强调 CSPRNG

6.1 UUIDv4 的本意就是"随机"

前面几章的道理,落到天天见的 UUID 上会很具体。RFC 9562 的 5.4 节一开头就写明:

UUIDv4 is meant for generating UUIDs from truly random or pseudorandom numbers.

——UUIDv4 本来就是为了用"真随机或伪随机的数"来生成 UUID。 同一节点出另一种做法:先取定量的随机位,再按规范填入版本位与变体位,其中:

randomly generate the exact required number of bits for random_a, random_b, and random_c (122 bits total)

——随机生成 random_a、random_b、random_c 所需的精确位数(合计 122 位),然后把版本与变体拼到规范规定的位置上。这里出现的是规范原文给出的 122 位这个数,不是本文推算出来的。

6.2 5.4 节把问题交给了 6.9 节

5.4 节最后一句是"关于随机数据生成的指导,见 6.9 节"。6.9 节的名字叫 Unguessability(不可猜性),全节就几行:

Implementations SHOULD utilize a cryptographically secure pseudorandom number generator (CSPRNG) to provide values that are both difficult to predict (“unguessable”) and have a low likelihood of collision (“unique”).

——实现应当(SHOULD)使用密码学安全的伪随机数生成器(CSPRNG),来提供**既"难以预测"(unguessable)又"不太可能重复"(unique)**的值。

这一句把本文前面所有的东西收进了一个术语:CSPRNG。“难预测"对应本文第二章讲的"猜不到”,"低重复可能"对应 UUID 这个场景本身对唯一性的要求。“伪随机”(pseudorandom)也在这里出现——关键在于它前面那两个字:“密码学安全”。 同样是伪随机,加不加这个限定,就是本文第三章那扇命门的分水岭。

6.3 为什么规范盯住"重新播种"

紧接着还有一句,容易被当成附带说明,其实很实在:

Take care to ensure the CSPRNG state is properly reseeded upon state changes, such as process forks, to ensure proper CSPRNG operation.

——要注意确保 CSPRNG 的状态在发生状态变化(例如进程 fork)时被正确地重新播种,以保证 CSPRNG 正常工作。

这句说明 CSPRNG 也不是"一个函数调完就万事大吉"。它维护着内部状态,而这个状态在进程被复制(fork)之后需要被重新播种,才不会让两个本应独立的副本行动一致。这正是规范用"应当(SHOULD)"并专门提一句注意的原因。

6.4 把三层串到 UUID 上

回头看,前面三章分别回答了三个问题,在这里正好各归其位:

  • 第二章回答的是"难在哪"——“看起来乱"不等于"猜不到”,所以要的是 CSPRNG 而不是普通伪随机。
  • 第三章回答的是"命门在哪"——种子和状态决定输出,所以 6.9 节才盯着"重新播种"。
  • 第四章回答的是"从哪来"——不可预测的源在操作系统那一层,所以 6.9 节点名要的是"系统能提供的最安全随机源"那一路。

本章可以带走的一句:UUIDv4 要的从来不只是"随机",规范用的是"应当使用 CSPRNG"——它要的是"难预测 + 低重复",而这个区别,就是"伪随机"前面那两个字的分量。

七、总结与自查

7.1 一条可以带走的判断链

  1. 先问这个值要不要"猜不到"。要,进第 2 步;不要(模拟、抽样、造样例),伪随机生成器就够。
  2. 要"猜不到",就别停在"看起来乱"上。能过统计检验、或源头范围有限(比如时钟),都可能栽(RN03)。
  3. 检查种子和状态:是接在操作系统熵源上,还是自己造了个种子薄薄的生成器(RN04 的例子 + 本机实测)。
  4. 顺着链子往左看:内核熵源 → 系统调用 → 用户态 API,看自己那一行最终接到哪一站(/dev/random / getentropy(2) / arc4random(3))。
  5. 选库函数时认准官方口径:要猜不到,用 secrets 一类;random 的文档自己说了它不适合(RN08 / RN10)。
  6. 涉及 UUID 这类带规范的东西,看规范怎么要求——UUIDv4 那句是"应当使用 CSPRNG",还附带"进程 fork 后要正确重新播种"(RN11 / RN12)。

这条链子里最值钱的是第 1 步:大多数用错随机数的事故,不是选错了算法,而是压根没问过"这个值要不要猜不到"。

7.2 一份自查清单

自查项为什么问这一条
这个值是"给人看的样例",还是"要防人猜的凭据"?两种要求不同,这是所有选择的分岔口
我是不是把"能过统计检验"当成了"猜不到"?RFC 4086 §1 明说这两件事不等价
我的随机数,种子是从操作系统熵源来的吗?种子决定输出,种子薄则全线薄(RN04)
我写的那行代码,最终接到的是熵源还是自造生成器?顺着"内核 → 系统调用 → 用户态 API"往左核
我有没有先看官方文档对这两个模块的定性?secrets 与 random 的适用面,文档写得清清楚楚
涉及 UUID 这类规范时,我看的是规范原文还是想当然?规范用的是"应当使用 CSPRNG",还带重新播种的要求

7.3 本文的使用限制

  • 不写"怎么猜、怎么试出某个随机数或那串标识"的任何思路或步骤,这类内容不在本文范围内。
  • 只引用官方原文给出的数字(如 RN04 的 256 与 2^128、secrets 文档的 32 字节、RFC 9562 的 122 位),不另外做数值推算。
  • 不对 Linux 侧 /dev/random 与 /dev/urandom 的实现下任何结论:本文引用的那段 Linux 描述,出处是 Darwin 手册中顺带描述 Linux 的段落。
  • 不涉及编码,也不引任何报错文本,不涉及口令破解内容与具体产品、库的漏洞。
  • 凡涉及"目前 / 最新 / 已"这类状态的判断,一律以 截至 2026-10-14 为界。

7.4 总结

回到开头那句话:“这里取个随机数。”

这句代码在两种场合长得一模一样,要求却完全不同:做模拟要的是"看起来乱",生成 token / 密钥 / 会话标识要的是"猜不到"。标准原文把区别讲得很直接——只过传统统计检验的伪随机数据会失败,基于时钟这类范围有限的源也会失败,结果是"伪安全";而种子的厚度决定整串输出的厚度,官方那个"8 位种子配 128 位密钥"的例子,与本机上"同一种子两次输出逐位一致"的实测,是同一件事的两面。

要真正"猜不到",就得落到操作系统提供的熵源上——内核随机设备是源,系统调用与用户态 API 是同一件事的两层入口;选择的那一刻,官方文档也把话说明白了:要安全,用 secrets 一类;random 自己写了它只做建模与仿真。 到了 UUID 这种带规范的东西上,规范用的词是"应当使用 CSPRNG",还提醒进程 fork 之后要正确重新播种。

所以,问题从来不是"你能不能自己写一个随机数",而是你有没有先问清楚:这个值,要不要猜不到。

配套资料:把全文的"两种尺子、种子命门、熵源三层、库函数怎么选、UUID 与 CSPRNG"收成一页速查卡,连同这份自查清单放在资料包里,扫码即可获取:

配套资料获取

本章可以带走的一句:把"要不要猜不到"当成第一问,再顺着"种子 → 熵源三层 → 库函数 → 规范要求"一路核下去,随机数就不再是一个可以随手写下的词。

附表 A:本文引用事实与官方出处对照表

#事实(一句)出处(来源名 + 具体位置)核验日期本文位置
1伪随机过程生成"用于保密的量"会导致"伪安全",对手复现出产生它的环境后可能比在完整空间里搜更省力RFC 4086 Abstract(BCP 106)2026-10-14第 2 章
2一切密码系统的核心是生成"保密的、猜不到的"数字;缺少真正不可预测的源是密码学软件设计的"开放伤口";只过统计检验或基于时钟这类有限源会失败RFC 4086 §12026-10-14第 2 章
3128 位密钥若由固定伪随机生成器配 8 位种子导出,对手只需搜 256 把而非 2^128 把,密钥里只有 8 位"信息"RFC 4086 §32026-10-14第 3 章
4同一种子两次取 random.random() 得到完全一致的序列,secrets.token_hex(8) 两次结果不同;Python 3.13.12本机实测(Python 脚本)2026-10-14 本机实测第 3 章
5random 设备产出均匀分布、质量可能很高的随机字节;getentropy(2) 对文件描述符耗尽、chroot、沙箱更有韧性;arc4random(3) 建立在 random 数据源之上且比直接访问系统随机设备更受推荐macOS man 4 random2026-10-14第 4 章
6随机设备实现 Fortuna 算法并维护熵池;/dev/urandom 是"对 Linux 的兼容让步",其后一段是手册描述 Linux 的内容macOS man 4 random2026-10-14第 4 章
7本机 /dev/random 与 /dev/urandom 均为字符设备(属性以 c 开头,属主 root wheel)本机实测(ls -l /dev/random /dev/urandom)2026-10-14 本机实测第 4 章
8secrets 生成密码学强度的随机数,适用于口令、账号认证、安全 token 等;应优先于 random 的默认伪随机生成器,后者为建模与仿真设计Python 官方文档 · secrets2026-10-14第 5 章
9random 模块的伪随机生成器不应用于安全目的,完全不适合密码学用途;randbytes 不应生成安全 tokenPython 官方文档 · random2026-10-14第 5 章
10截至 2015 年,32 字节(256 位)随机性足以覆盖 secrets 典型用例;标准随算力提高而提高Python 官方文档 · secrets(How many bytes should tokens use?)2026-10-14第 5 章
11本机 secrets.DEFAULT_ENTROPY 为 32,是 token_* 系列未指定长度时默认使用的量本机实测(secrets.DEFAULT_ENTROPY)2026-10-14 本机实测第 5 章
12UUIDv4 用于从真随机或伪随机数生成 UUID;实现可取 122 位随机位填入各字段RFC 9562 §5.42026-10-14第 6 章
13实现应当使用 CSPRNG 提供"难预测且低重复"的值;并须在进程 fork 等状态变化后正确重新播种RFC 9562 §6.92026-10-14第 6 章
14getentropy(2) 的调用形状示意为形状说明,未在本机编译运行,标注"代码待验证"本文说明2026-10-14第 4 章

附表 B:术语速查表

术语一句话解释易混点
伪随机由一个确定的初始状态、按确定规则"长"出来的数列“看起来乱"不等于"猜不到”,这是全文的分岔口
密码学随机 / CSPRNG为"猜不到"设计的随机源,通常接到操作系统熵源它也是伪随机,区别在那句"密码学安全"的限定
熵源操作系统用来收集不可预测性的那套底层来源它才是"真正不可预测"通常落脚的地方
种子伪随机生成器的初始值种子有多薄,输出就有多薄;可复现是它的设计目标
“伪安全”RFC 4086 给的词:用伪随机过程生成保密量的后果对手只要复现产生它的环境,就能把空间缩小
/dev/random、/dev/urandom系统上读取随机字节的两个设备名两者在 Linux 上的关系不在本文结论范围内
getentropy(2)、arc4random(3)取随机字节的系统调用接口,以及建立在系统随机源之上的用户态生成器官方更推荐用它们,而不是直接访问系统的随机设备
secretsPython 里为"保密"设计的随机模块文档明说它应优先于 random 的默认生成器
randomPython 里为建模与仿真设计的伪随机模块官方警告它不应被用于安全目的
UUIDv4用真随机或伪随机数生成的 UUID规范要求"应当使用 CSPRNG",并注意重新播种
重新播种在进程 fork 等状态变化后重设 CSPRNG 内部状态不做这件事,副本之间可能行动一致

写在最后:这篇用到的资料

写这篇文章时,我把自己脚本里那句"随手取个随机数"重新拆了一遍,发现真正要问的不是"用哪个函数",而是"这个值要不要猜不到"——一旦问出口,种子、熵源、库函数、规范要求就都串成了一条线。顺手也整理了几份配套的东西:

  • 靶场环境对照表:DVWA、upload-labs 在 Windows / macOS / Linux 三平台的可行性与推荐路径
  • Web 安全学习路线图:从基础打牢到安全管理,四个阶段各学什么
  • 常用靶场清单:每个靶场练什么、适合哪个阶段

资料是我自己整理的,放在下面这个码上,扫码即可获取:

配套资料获取

Web 安全学习路线图

资料目录预览

添加时备注「靶场」,优先通过。

拿到之后建议先看环境对照表那一份,它按"哪一层出问题、用哪一把尺子"整理,跟本文"先问要不要猜不到、再顺着链子往左核"是一条线。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐