安全相关的随机数:为什么不能直接用 rand()

密码学 · 3 分钟阅读· 279 次阅读

用 rand() 生成密码重置 token,攻击者可以通过种子推算出下一个值——这类漏洞在 CTF 和真实系统里都常见。

安全场景必须用密码学安全随机数(CSPRNG),区别在于「不可预测」。

先说结论

token 用 CSPRNG 生成 128 位以上,编码成 URL 安全字符串。

  • Python 用 secrets,Java 用 SecureRandom,PHP 用 random_bytes
  • UUIDv4 可用于标识,不用于高价值 token
  • token 要有有效期与一次性
  • 不要用时间戳/自增 ID 拼随机

漏洞是怎么产生的

普通 PRNG 的目标是「分布均匀」,CSPRNG 的目标是「不可预测」。前者可被反推,后者不行。

长度也重要:64 位随机在生日碰撞下并不够,安全 token 建议 128 位以上。

修复与验证

修复不是改一行代码,而是四件事一起做:

  • 盘点 token 生成点:会话、重置密码、邀请、API Key
  • 改用语言标准库的 CSPRNG
  • 长度 ≥ 128 位,URL 安全编码
  • 设置有效期与使用次数限制
  • 存储时哈希,避免库泄露即失守

攻击面与检测点

按影响面排序,先修影响最大的:

语言 正确 API 错误用法
Python secrets.token_urlsafe random.random
PHP random_bytes / random_int rand / mt_rand
Java SecureRandom java.util.Random
Go crypto/rand math/rand

安全相关的随机数

几个容易踩的坑

下面这些是最常见的错误做法:

  • 用时间戳做种子:可枚举
  • token 太短:可暴力枚举
  • token 长期有效:泄露即长期可用
  • 把 token 明文存库:拖库后可冒用

写在最后

安全随机数的判断标准只有一个:拿到一批输出,能不能预测下一个。

安全不是一次加固,是持续的假设:假设输入不可信、假设边界会破、假设有人会看错。

评论 (3)

半
半箱油

修复清单比漏洞描述有用多了,很多文章只讲怎么打不讲怎么防。

白
白帽小林

白名单那条永远是最有效的,正则黑名单迟早绕过。

运
运维老张

建议再补一条:把这类检查加到 CI 里,靠人记必然漏。

发表评论

验证码

提交后需站长审核,通过后才会显示。