为什么在密码问题上char[]优先于String?

本文探讨了在密码处理中使用char[]而非String的原因,解释了String的不可变性可能导致的安全风险,并提供了使用char[]降低攻击窗口的解释。同时,通过代码示例展示了直接打印String和char[]的不同后果。

问题

Swing中,密码域(JPasswordField)用getPassword()函数(用来返回char[])取代getText()函数(返回字符串)。在工作中我得到类似的建议是不要用字符串去处理密码相关的问题,为什么涉及到密码问题时字符串会对安全构成威胁呢?(译注:这是提问者在Stackoverflow提了问题,他觉得用char[]处理密码并没有String方便,但为什么还要推荐使用char[]处理呢?下面是几个比较精彩的回答)。

Why is char[] preferred over String for passwords?

In Swing, the password field has a getPassword() (returns char[]) method instead of the usual getText() (returns String) method. Similarly, I have come across a suggestion not to use Strings to handle passwords. Why does String pose a threat to security when it comes to passwords?

It feels inconvenient to use char[].

回答1

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

而对于数组,可以在该数组处理它之后再显示地擦掉数组中内容,可以以任何方式把数组内容覆盖掉,即使是GC触发前密码也不会出现在系统的任何地方。

所以,这是从安全角度来选择的,但是即便是用char[]也只是降低被攻击的概率而已,还是会有一些特定的手法攻破数组处理的密码。

Strings are immutable. That means once you've created the string, if another process can dump memory, there's no way (aside from reflection) you can get rid of the data before GC kicks in.

With an array, you can explicitly wipe the data after you're done with it: you can overwrite the array with anything you like, and the password won't be present anywhere in the system, even before garbage collection.

So yes, this is a security concern - but even using char[] only reduces the window of opportunity for an attacker, and it's only for this specific type of attack.

EDIT: As noted in comments, it's possible that arrays being moved by the garbage collector will leave stray copies of the data in memory. I believe this is implementation-specific - the GC may clear all memory as it goes, to avoid this sort of thing. Even if it does, there's still the time during which the char[] contains the actual characters as an attack window.

回答2

从另一方面来,若是普通的字符串,有时你会不经意间打印密码到日志中或者其他不安全的地方,而char[] 就没那么显而易见

参考一下这段代码:

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

输出结果:

1
String: PasswordArray: [C@5829428e

While other suggestions here seem valid, there is one other good reason. With plain String you have much higher chances of accidentally printing the password to logs, monitors or some other insecure place. char[] is less vulnerable.

Consider this:

public static void main(String[] args) {
    Object pw = "Password";
    System.out.println("String: " + pw);

    pw = "Password".toCharArray();
    System.out.println("Array: " + pw);
}

Prints:

String: Password
Array: [C@5829428e

回答3

引用官方的文Java加密体系结构指南说到char[] vs String。在对象java.lang.String中收集和存储密码看似符合逻辑,但是字符串对象是不可变的,没有任何方法可以改变(重写)或清空内容。这一特性使得字符串对象不适合存储安全敏感信息,比如用户密码。你应当使用一个字符数组来代替,以便收集和存储安全敏感的信息。安全编码指南4.0也提到了类似的问题。

回答4

字符数组(char[])在使用之后里面的元素可以被清除,字符串并不如此。如果有人能以某种方式看到内存映像,如果字符串被使用了,它们可以以纯文本方式看到密码。但如果是char[], 看到的是清除后的数据(用0替换的数据),这种方式是安全的。

最后的思考

尽管使用char[]并不能保证足够安全,但我也建议使用hash’d或者加密的密码来代替普通的文本字符串密码,而且使用完后立即清除。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值