伪随机数生成器只要状态、算法或输出泄露得足够多,就可能被预测。游戏中的随机掉落、抽样和模拟常可接受可复现的伪随机序列,认证令牌、密码重置链接和会话标识则必须使用密码学安全随机源。设计时先分清这两类用途,比后来给普通随机函数补救更可靠。
伪随机数为什么能复现
多数伪随机数生成器从一个初始种子开始,根据确定性算法更新内部状态。同样的种子和调用顺序会得到同样的输出,这对测试、回放和模拟很有帮助。代价是算法结构一旦被了解,攻击者可能通过输出反推状态或枚举种子。时间戳、进程号和递增计数器都不适合作为安全种子。
哪些场景必须使用安全随机源
只要猜中下一个值会让攻击者获得身份、资金或权限,就应使用操作系统提供的密码学安全随机接口。它的目标是让攻击者即使看到部分输出,也难以推断后续输出。
- 登录会话和访问令牌
- 密码重置链接与一次性验证码
- 加密密钥、初始化向量和盐值
- 抽奖、匹配等存在对抗动机的结果
普通 PRNG 可以继续用于动画、随机地图、测试数据和非安全模拟。
如何检查现有代码
先全局定位随机数调用,再按业务后果分类。不要只看函数名,许多项目把随机逻辑封装在工具类或第三方库中。
- 找出每个随机值最终影响的功能。
- 检查种子是否来自可预测输入。
- 确认安全场景使用系统安全随机接口。
- 检查日志、错误页和 API 是否会暴露完整随机值。
测试中若需要可复现输出,可以注入固定种子实现,但生产实现必须与测试实现分开配置。
游戏与模拟的特殊需要
游戏常需要让服务器和客户端对同一局面得到一致结果,或让开发者复现一个罕见 Bug。此时可以保存种子和调用次数,但涉及奖励、排名或对战公平性时,关键随机决策应由可信服务端产生。客户端提前知道完整序列,会给篡改和预测留下空间。
常见误区
把随机值编码成十六进制或 Base64 不会增加熵,只改变展示方式。频繁重新播种也可能降低质量,尤其是种子来自低分辨率时间。安全随机源生成速度通常足够处理令牌和密钥,性能优化前应先确认真实瓶颈。
FAQ
随机数测试通过就安全了吗
不一定。统计分布看起来均匀,仍可能让攻击者预测后续输出。
能否给通用随机函数加密哈希
不能简单保证安全。应直接使用经过安全设计的随机源。
上线前做一次对抗检查
让没有参与实现的人从公开接口、页面源码、日志样例和错误信息中寻找种子线索。重点检查响应时间、递增编号、调试字段和可重复请求是否暴露序列位置。发现问题后应轮换受影响令牌或密钥,仅替换随机函数并不能让已经发出的可预测凭据自动失效。