
在日常语言中,“随机”意味着不可预测。在数学和计算机科学中,随机性有精确的含义:如果知道所有先前的值对预测下一个值毫无帮助,那么这个序列就是随机的。在确定性机器中实现真正的随机性从根本上来说是困难的——计算机遵循精确的指令,这与不可预测性恰恰相反。解决这一问题的方案分为两大类:伪随机数生成器(PRNG)和真随机数生成器(TRNG)。
PRNG 是一种确定性算法,它生成一个看起来随机的数列,但实际上完全由一个称为种子的初始值决定。给定相同的种子,PRNG 总会产生相同的序列。这听起来像是一个缺陷,但在许多场景下实际上是一个有用的特性。
目前最广泛使用的现代 PRNG 是梅森旋转算法,其周期为 2^19937 − 1(即在重复之前能生成那么多个值)。它几乎能通过所有统计随机性测试。大多数编程语言中的通用随机函数——Python 的 random 模块、Java 的 java.util.Random、JavaScript 的 Math.random()——底层都使用 PRNG。
关键限制:PRNG 不具备密码学安全性。如果攻击者能够观察到足够多的输出,他们就能重建内部状态并预测所有未来的输出。对于任何安全敏感的场景,绝不能使用 PRNG。
CSPRNG 是专为计算上不可预测而设计的 PRNG,即使知道之前的输出也无法预测。它通过密码学单向函数实现这一点,并以真实熵源作为种子。操作系统通过 Linux/macOS 上的 /dev/urandom 和 Windows 上的 CryptGenRandom 等接口提供 CSPRNG。
在应用代码中:
secrets 模块(用于密码和令牌,而非 random)crypto.randomBytes() 和 crypto.randomUUID()window.crypto.getRandomValues()java.security.SecureRandom对于安全敏感的操作,始终使用密码学随机 API:生成密码、令牌、会话 ID、API 密钥、密码学密钥和随机数。
TRNG 从真正不可预测的物理过程中获取随机性:电子元件中的热噪声、放射性衰变、大气噪声或光子到达时间。银行和证书颁发机构使用的硬件安全模块(HSM)包含 TRNG。random.org 等服务从大气噪声中生成随机数,常被用作彩票和竞赛中可验证的公平随机源。
操作系统的 CSPRNG 通常从硬件熵源(键盘计时、磁盘 I/O、Intel RDRAND 等硬件 RNG 芯片)中自我播种,然后使用 CSPRNG 算法将该熵扩展成数据流。这种混合方式兼具硬件熵的不可预测性和软件生成的速度。
Math.random() 或同类函数用于这些场景。当可重现性很重要时——重现特定测试场景、共享生成的结果、调试模拟——你可以用固定值作为 PRNG 的种子,每次都能获得相同的输出。许多游戏使用种子进行世界生成,让玩家可以分享有趣地图的种子。机器学习研究者通常在实验开始时设定随机库的种子,以确保跨运行的可重现性。
种子的质量同样重要。以毫秒级当前时间戳作为 PRNG 种子是可预测的,如果攻击者大致知道你的应用程序何时启动的话。对于非安全目的,时间戳种子通常没问题;但对于输出必须无法猜测的任何场景,请使用 CSPRNG 来生成种子。
打开免费随机数生成器——在浏览器中生成任意范围内的单个或多个随机数,支持有无重复两种模式。