Why is char[] preferred over String for passwords?

2018-12-30 23:58发布

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 String to handle passwords.

Why does String pose a threat to security when it comes to passwords? It feels inconvenient to use char[].

18条回答
谁念西风独自凉
2楼-- · 2018-12-31 00:32

As Jon Skeet states, there is no way except by using reflection.

However, if reflection is an option for you, you can do this.

public static void main(String[] args) {
    System.out.println("please enter a password");
    // don't actually do this, this is an example only.
    Scanner in = new Scanner(System.in);
    String password = in.nextLine();
    usePassword(password);

    clearString(password);

    System.out.println("password: '" + password + "'");
}

private static void usePassword(String password) {

}

private static void clearString(String password) {
    try {
        Field value = String.class.getDeclaredField("value");
        value.setAccessible(true);
        char[] chars = (char[]) value.get(password);
        Arrays.fill(chars, '*');
    } catch (Exception e) {
        throw new AssertionError(e);
    }
}

when run

please enter a password
hello world
password: '***********'

Note: if the String's char[] has been copied as a part of a GC cycle, there is a chance the previous copy is somewhere in memory.

This old copy wouldn't appear in a heap dump, but if you have direct access to the raw memory of the process you could see it. In general you should avoid anyone having such access.

查看更多
琉璃瓶的回忆
3楼-- · 2018-12-31 00:32

There is nothing that char array gives you vs String unless you clean it up manually after use, and I haven't seen anyone actually doing that. So to me the preference of char[] vs String is a little exaggerated.

Take a look at the widely used Spring Security library here and ask yourself - are Spring Security guys incompetent or char[] passwords just don't make much sense. When some nasty hacker grabs memory dumps of your RAM be sure she'll get all the passwords even if you use sophisticated ways to hide them.

However, Java changes all the time, and some scary features like String Deduplication feature of Java 8 might intern String objects without your knowledge. But that's different conversation.

查看更多
十年一品温如言
4楼-- · 2018-12-31 00:32

Strings are immutable and cannot be altered once they have been created. Creating a password as a string will leave stray references to the password on the heap or on the String pool. Now if someone takes a heap dump of the Java process and carefully scans through he might be able to guess the passwords. Of course these non used strings will be garbage collected but that depends on when the GC kicks in.

On the other side char[] are mutable as soon as the authentication is done you can overwrite them with any character like all M's or backslashes. Now even if someone takes a heap dump he might not be able to get the passwords which are not currently in use. This gives you more control in the sense like clearing the Object content yourself vs waiting for the GC to do it.

查看更多
无色无味的生活
5楼-- · 2018-12-31 00:33

I don't think this is a valid suggestion, but, I can at least guess at the reason.

I think the motivation is wanting to make sure that you can erase all trace of the password in memory promptly and with certainty after it is used. With a char[] you could overwrite each element of the array with a blank or something for sure. You can't edit the internal value of a String that way.

But that alone isn't a good answer; why not just make sure a reference to the char[] or String doesn't escape? Then there's no security issue. But the thing is that String objects can be intern()ed in theory and kept alive inside the constant pool. I suppose using char[] forbids this possibility.

查看更多
余生请多指教
6楼-- · 2018-12-31 00:36

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 garbage collection 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.

As noted in the 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 garbage collector 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.

查看更多
余生无你
7楼-- · 2018-12-31 00:36

Using password into String or Char[] is always debatable because both the approaches had their own utility and disadvantage as well. It depending upon the need which user is expecting to be fulfilled. Below lines may help better in understanding when to use which container : Since String in java is immutable, whenever some tries to manipulate your string it creates a new Object and existing remains untempered. This could be seen as advantage for storing password as String but on the other hand. String object remains in memory even after use. So somehow if anyone got the memory location can easily trace your password stored at that location. While coming to Char[] which is mutable but it had advantage that after usage, programmer can explicilty clean the array or override values. So that after no use it is cleaned and no one could ever know about the information what you had stored.

Based on above circumstances may be one can get Idea whether to go with String or Char[] for their requirement.

Thanks.

查看更多
登录 后发表回答