String不可变性不利于密码安全,因其明文易驻留内存;应改用可清空的char[],并立即哈希加盐存储。

Java 中 String 的不可变性本身并不适合直接用于密码存储,反而可能带来安全风险。它不能替代加密、哈希等密码学实践,但理解其特性有助于规避常见陷阱。
String 不可变性在密码处理中的潜在风险
String 对象一旦创建就无法修改,所有“修改”操作(如 substring、replace、字符串拼接)都会生成新对象,旧对象仍留在内存中,直到被垃圾回收。这意味着:
- 明文密码以 String 形式存在时,可能在堆内存中驻留较长时间,增加被内存转储(memory dump)工具读取的风险;
- 即使代码中立即将 String 变量置为
null,原字符串对象仍可能在字符串常量池或堆中残留; - String 会被 JVM 优化缓存(如 intern),进一步延长生命周期。
更安全的替代方案:用 char[] 处理敏感字符
Java 官方推荐使用 char[] 存储密码(例如 JPasswordField.getPassword() 返回的就是 char[]),原因在于:
-
char[]是可变的,使用完毕后可主动清空:Arrays.fill(password, '\0');; - 不会被字符串常量池缓存,打印时也不会意外输出明文(
System.out.println(charArr)输出的是地址,而非内容); - 生命周期可控,配合作用域限制和及时清理,能显著降低内存泄露风险。
密码存储的正确做法(与 String 特性无关)
无论用 String 还是 char[],密码绝不能以明文形式存储**。生产环境必须遵循以下原则:
- 输入后立即转换为
char[],完成哈希计算后立刻清空; - 使用强哈希算法(如
bcrypt、scrypt或Argon2),而非 MD5/SHA-1; - 哈希时必须加盐(salt),且每个密码使用独立随机 salt;
- 数据库中只保存哈希值和 salt(通常合并为一个字段),绝不存原始密码。
小结:不可变性不是保护机制,而是设计约束
String 的不可变性保障了线程安全和哈希一致性,但它让敏感数据更难及时清除。在密码场景中,这不是优势,而是需要绕开的限制。真正起保护作用的是及时清理、单向哈希、加盐和慢哈希算法——这些都与 String 是否可变无关。用对工具,比用“看起来安全”的特性更重要。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











