INFO5995-Task3-修复方案分析
修复方案
SecureRandom secureRandom = new SecureRandom(); |
SecureRandom 和 Random 的三个关键区别
区别 1:种子大小
| Random | SecureRandom | |
|---|---|---|
| 种子大小 | 48 位 | ≥ 128 位 |
| 暴力破解 | 几天可破 | 不可能(当前算力) |
Random: 2^48 ≈ 2.8 × 10^14 可能值 |
差距是 10^24 倍——不是几千几万倍,是一万亿万亿倍。
区别 2:熵源
Random 的熵源: - 种子是确定性的 - 相同种子 → 相同序列
SecureRandom 的熵源: - 从操作系统获取真随机数 -
Android 上通常来自 /dev/urandom -
基于硬件噪声、时钟、进程状态等
操作系统真随机数池 |
区别 3:密码学安全性
Random 不满足任何密码学安全属性:
- 给定一些输出,可以反推种子
- 可以预测未来所有输出
SecureRandom 设计目标就是密码学安全:
- 下一位测试(Next Bit Test):没有任何多项式时间算法能以大于 1/2 的概率预测出下一位
- 不可预测性:即使知道之前的输出,也无法预测下一个
量化对比
| 属性 | Random | SecureRandom |
|---|---|---|
| 种子大小 | 48-bit | ≥128-bit |
| 算法确定性 | ✅ 是 | ❌ 否(每次从 OS 获取新熵) |
| 暴力破解时间 | 几天 | 不可能 |
| 满足 Next Bit Test | ❌ | ✅ |
| 适合生成 Token | ❌ | ✅ |
在这个 App 里怎么改
修改前: private String generateSessionToken() {
Random random = new Random(); // 弱随机数
StringBuilder sb = new StringBuilder(16);
for (int i = 0; i < 16; i++) {
sb.append("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
.charAt(random.nextInt(62)));
}
return sb.toString();
}
修改后: private String generateSessionToken() {
SecureRandom secureRandom = new SecureRandom();
StringBuilder sb = new StringBuilder(16);
for (int i = 0; i < 16; i++) {
sb.append("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
.charAt(secureRandom.nextInt(62)));
}
return sb.toString();
}
一行之差:new Random() →
new SecureRandom()
关于明文凭证存储的修复
EncryptedSharedPreferences(Android Jetpack
Security):
- 用 AES-256-GCM 加密存储内容
- 密钥存在 Android Keystore System 里
- 即使设备被 Root,攻击者也拿不到密钥
这是解决支撑发现(CWE-312)的最直接方案。