不安全的随机数漏洞与防护
字数 1136 2025-11-07 12:33:56
不安全的随机数漏洞与防护
1. 漏洞描述
不安全的随机数漏洞是指开发者在需要生成随机值的场景(如生成令牌、密码重置链接、加密密钥等)中,使用了可预测或弱随机数生成器,导致攻击者能够推测出随机值,进而绕过授权、劫持会话或伪造数据。例如,使用时间戳或简单算法作为“随机源”即属于典型错误。
2. 漏洞原理与风险场景
- 弱随机数生成器:
- 如C/C++中的
rand()、PHP中的rand()或Java的Random类,这些伪随机数生成器(PRNG)依赖固定种子(如系统时间),攻击者若获知种子或部分输出,可推演后续随机数。 - 示例:若使用
rand()生成6位数字验证码,且种子为当前秒数,攻击者尝试常见时间戳即可覆盖可能范围。
- 如C/C++中的
- 熵源不足:
- 在加密场景中,随机数需要足够的熵(随机性来源)。若系统熵池不足(如虚拟机刚启动时),可能导致随机数重复或规律性强。
- 风险场景:
- 密码重置令牌、CSRF Token、Session ID等关键数据若可预测,攻击者可直接篡改他人账户或越权操作。
3. 漏洞验证方法
- 黑盒测试:
- 收集多次生成的随机值(如连续获取10个验证码),统计分布规律或尝试破解生成算法。
- 检查随机值是否包含时间戳、用户ID等易猜测信息。
- 代码审计:
- 搜索代码中的随机数生成函数(如
Math.random()、Random.nextInt()),确认是否使用密码学安全的替代方案。
- 搜索代码中的随机数生成函数(如
4. 安全防护方案
- 使用密码学安全的随机数生成器(CSPRNG):
- Java:用
java.security.SecureRandom替代Random类。 - Python:用
os.urandom()或secrets模块(如secrets.token_urlsafe())。 - PHP:用
random_int()而非rand()。
- Java:用
- 确保足够熵源:
- Linux系统可通过
/dev/random或/dev/urandom获取高熵随机数(后者在熵不足时不会阻塞,但更适用非加密场景)。
- Linux系统可通过
- 避免暴露随机种子:
- 禁止将时间、用户输入等易猜测值作为种子。
- 随机值长度与复杂度:
- 重要令牌长度需≥16字节,并包含字母、数字、符号混合字符集。
5. 实战案例
某系统用以下代码生成密码重置Token:
// 漏洞代码
$token = rand(100000, 999999); // 6位数字,基于时间种子
攻击者通过多次请求发现Token均以1xx开头,推测系统使用固定时间范围作为种子,最终爆破成功重置管理员密码。
修复代码:
// 安全代码
$token = bin2hex(random_bytes(16)); // 生成32字符十六进制随机数
6. 扩展思考
- 分布式系统中,若多个节点使用相同种子或低熵源,可能导致随机数冲突,需引入中心化随机数服务或硬件熵源(如TPM)。
- 对于验证码等场景,除随机数外,需结合频率限制、多次失败锁定等机制防御爆破。