漏洞 6(支撑):从本地文件读取并验证凭证

漏洞 6(支撑):从本地文件读取并验证凭证

代码证据

Login.java 第 77-93 行,凭证验证逻辑:

BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(openFileInput("credentials.txt")));
String str = bufferedReader.readLine();
if (str == null) {
return false;
}
String[] split = str.split(" ");
String trim = split[1].trim();
String trim2 = str.substring(split[0].length() + 1).trim();
return editText.getText().toString().trim().equals(trim)
&& editText2.getText().toString().trim().equals(trim2);

这段代码在做什么

  1. 打开 credentials.txt
  2. 读出存储的内容:"Username: alice Password: password123"
  3. 用空格分割字符串
  4. 提取出存的用户名和密码
  5. 和用户输入比较

验证逻辑

stored_username == input_username  AND  stored_password == input_password

等于:每次都把存在文件里的密码和输入的密码做明文比对。


有什么问题

问题 1:密码明文存储

(在漏洞 5 里已详述) - 如果文件被读取,密码直接暴露

问题 2:没有防暴力破解

  • 没有登录次数限制
  • 没有账户锁定机制
  • 攻击者可以无限次尝试

问题 3:比较是字符串相等

editText2.getText().toString().trim().equals(trim2)

这行代码做了字符串的直接比较

如果攻击者知道格式("Username: XXX Password: YYY"): - 可以在文件里改写新的凭证 - 或者通过分析文件格式构造恶意内容


和主漏洞的关系

这个发现在作业里的定位:

发现 类型 定位
java.util.Random 生成 session token CWE-338 主漏洞
明文凭证存储 + 本地验证 CWE-312 支撑发现

两者都真实存在于代码里,但:

主漏洞回答的是"随机数用错了"
支撑发现回答的是"凭证存得不够安全"


为什么支撑发现也很重要

即使 session token 的问题被修复了,如果凭证文件是明文存储的:

  • 攻击者通过其他途径(如物理访问、恶意软件)拿到文件
  • 就能知道用户的用户名和密码
  • 然后正常登录

两个漏洞叠加,攻击面更宽。


修复建议

针对这个支撑发现:

不要把密码明文存到文件里,而是:

// 好一点的方案:Hash 存储
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest(password.getBytes());
// 存 hash 而不是明文

// 更好的方案:用 Android 的 EncryptedSharedPreferences
// 用系统级密钥加密存储,连 Root 用户都拿不到明文

但最根本的修复还是: - 后端验证(不把密码存在本地) - 但这个 App 没有后端,所以用 EncryptedSharedPreferences 是最实际的方案