INFO5995-Task3-修复方案分析

修复方案

SecureRandom secureRandom = new SecureRandom();

SecureRandom 和 Random 的三个关键区别

区别 1:种子大小

Random SecureRandom
种子大小 48 位 ≥ 128 位
暴力破解 几天可破 不可能(当前算力)
Random:     2^482.8 × 10^14  可能值
SecureRandom: 2^1283.4 × 10^38 可能值

差距是 10^24 倍——不是几千几万倍,是一万亿万亿倍。


区别 2:熵源

Random 的熵源: - 种子是确定性的 - 相同种子 → 相同序列

SecureRandom 的熵源: - 从操作系统获取真随机数 - Android 上通常来自 /dev/urandom - 基于硬件噪声、时钟、进程状态等

操作系统真随机数池

SecureRandom 每次获取种子

输出在计算上不可预测

区别 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)的最直接方案。

INFO5995