为什么要使用字符数组存储密码

字符数组(char [])和字符串String都可以用于存储文本数据,但是在储存密码时该使用哪个呢?在Swing中,密码域(JPasswordField)用getPassword()函数(用来返回char[])取代了getText()函数(返回字符串)。但是,使用char[]处理密码并没有String方便,为什么还要推荐使用char[]处理呢?

String在Java中是不可变对象,如果作为普通文本存储密码,那么它会一直存在内存中直至被垃圾收集器回收。这就意味着一旦创建了一个字符串,如果另一个进程把尝试内存的数据导出(dump),在GC进行垃圾回收之前该字符串会一直保留在内存中,那么该进程就可以轻易的读取到该字符串。

而对于数组,可以在使用该数组之后显示地擦掉数组中的内容,你可以使用其他不相关的内容把数组内容覆盖掉,例如,在使用完密码后,我们将char[]的值均赋为0,如果有人能以某种方式看到内存映像,他只能看到一串0;而如果我们使用的是字符串,他们便能以纯文本方式看到密码。因此,使用char[]是相对安全的。

推荐使用char[],这是从安全角度来选择的。但是,我们应当注意到,即使是用char[]处理密码也只是降低被攻击的概率而已,还是会有其他方法攻破数组处理的密码。

另一方面,使用String的时候,你可能会不经意间将密码打印出来(如log文件),此时,使用char[]就显得更加的安全了,如:

1
2
3
4
5
6
public static void main(String[] args) {
Object pw = "Password";
System.out.println("String: " + pw);
pw = "Password".toCharArray();
System.out.println("Array: " + pw);
}

此时的输出结果将会是

String: Password
Array: [C@5829428e

实际上,即使使用了char[]保存密码也仍然不够安全,内存中还是可能会有这串数据的零碎副本,因此,建议使用加密的密码来代替普通的文本字符串密码,并且在使用完后记得立即清除。

整理自stackoverflow