不安全的随机数漏洞与防护
字数 1101 2025-11-09 02:33:02
不安全的随机数漏洞与防护
1. 漏洞描述
不安全的随机数漏洞是指开发者在需要生成随机值(如加密密钥、会话令牌、验证码、密码重置令牌等)时,使用了可预测或弱随机数生成器(PRNG),导致攻击者能够推测出随机数序列,进而绕过安全机制。例如,使用时间戳、进程ID或线性同余生成器(LCG)等伪随机源,可能被逆向或统计攻击破解。
2. 漏洞原理
2.1 随机数生成器的类型
- 真随机数生成器(TRNG):基于物理熵源(如硬件噪声、鼠标移动),不可预测。
- 伪随机数生成器(PRNG):基于确定性算法和种子(Seed)生成序列,若种子或算法弱,则输出可预测。
2.2 常见错误实践
- 使用时间戳、进程ID等低熵值作为唯一种子(如
rand()、System.Random)。 - 重复使用相同种子(如每次重启后重置种子)。
- 使用已知不安全的算法(如C语言
rand()默认实现为LCG)。
2.3 攻击场景
- 预测密码重置令牌,劫持用户账户。
- 破解加密密钥,解密敏感数据。
- 伪造会话ID,发起会话劫持。
3. 漏洞示例
3.1 弱随机数生成代码(Python)
import random
import time
# 错误示例:使用时间戳作为种子
random.seed(int(time.time()))
token = random.randint(100000, 999999) # 6位验证码
攻击者若知道生成时间戳的近似范围,可枚举种子并重现序列。
3.2 弱随机数生成代码(Java)
// 错误示例:使用默认种子(系统时间)
Random rand = new Random();
int sessionId = rand.nextInt();
Random类默认种子为系统时间,攻击者可通过多次采样推测序列。
4. 安全防护方案
4.1 使用密码学安全的随机数生成器(CSPRNG)
- 原则:选择经过验证的CSPRNG,其设计可抵抗密码学分析。
- 示例代码:
- Python:
import secrets token = secrets.randbelow(1000000) # 生成0-999999的随机数 key = secrets.token_hex(32) # 生成256位密钥 - Java:
import java.security.SecureRandom; SecureRandom csprng = new SecureRandom(); byte[] key = new byte[32]; csprng.nextBytes(key); - C#:
using System.Security.Cryptography; byte[] key = new byte[32]; RandomNumberGenerator.Fill(key);
- Python:
4.2 确保足够的熵源
- 避免手动设置弱种子(如时间戳)。
- 系统熵源不足时(如虚拟机),结合硬件熵源或使用
/dev/urandom(Linux)、BCryptGenRandom(Windows)。
4.3 随机数的使用场景区分
- 安全敏感场景(如密钥、令牌):必须使用CSPRNG。
- 非安全场景(如游戏随机数):可使用普通PRNG。
5. 防护实践检查清单
- [ ] 禁止使用
rand()、Math.random()等非安全随机函数生成安全凭据。 - [ ] 使用标准库的CSPRNG(如
secrets、SecureRandom)。 - [ ] 随机数长度需满足安全要求(如会话ID至少128位)。
- [ ] 对生成的随机值进行安全存储与传输(如哈希后存储)。
6. 总结
不安全的随机数漏洞源于对伪随机数生成器的误用,通过替换为密码学安全的随机数生成器(CSPRNG)、确保强熵源、区分使用场景,可有效避免预测风险。在安全开发中,应始终审视随机数的生成逻辑,避免隐性漏洞。