1. Overview
In this article, we’ll explain why we should use char[] array for representing passwords instead of String in Java.
Please note that this tutorial focuses on the ways of manipulating passwords in the memory, not on the actual ways of storing them, which usually is handled in the persistence layer.
We also assume that we can’t control the format of the password (e.g. the password comes from the 3rd party API in the form of the String). Although it’d seem obvious to use object of type java.lang.String for manipulating passwords, it’s recommended by Java team themselves to use char[] instead.
For instance, if we have a look at the JPasswordField of javax.swing, we can see that the method getText() which returns String is deprecated since Java 2 and is replaced by getPassword() method which returns char[].
So, let’s explore a few strong reasons why that’s the case.
2. Strings Are Immutable
Strings in Java are immutable which means that we cannot change them using any high-level APIs. Any change on a String object will produce a new String, keeping the old one in memory.
Therefore, the password stored in a String will be available in memory until Garbage Collector clears it. We cannot control when it happens, but this period can be significantly longer than for regular objects since Strings are kept in a String Pool for re-usability purpose.
Consequently, anyone with access to the memory dump can retrieve the password from memory.
With a char[] array instead of the String, we can explicitly wipe data after we finish with intended work. This way, we’ll ensure that password is removed from memory even before garbage collection takes place.
Let’s now take a look at code snippets, which demonstrate what we’ve just discussed.
First for String:
System.out.print("Original String password value: ");
System.out.println(stringPassword);
System.out.println("Original String password hashCode: "
+ Integer.toHexString(stringPassword.hashCode()));
String newString = "********";
stringPassword.replace(stringPassword, newString);
System.out.print("String password value after trying to replace it: ");
System.out.println(stringPassword);
System.out.println(
"hashCode after trying to replace the original String: "
+ Integer.toHexString(stringPassword.hashCode()));
The output will be:
Original String password value: password
Original String password hashCode: 4889ba9b
String value after trying to replace it: password
hashCode after trying to replace the original String: 4889ba9b
Now for char[]:
char[] charPassword = new char[]{'p', 'a', 's', 's', 'w', 'o', 'r', 'd'};
System.out.print("Original char password value: ");
System.out.println(charPassword);
System.out.println(
"Original char password hashCode: "
+ Integer.toHexString(charPassword.hashCode()));
Arrays.fill(charPassword, '*');
System.out.print("Changed char password value: ");
System.out.println(charPassword);
System.out.println(
"Changed char password hashCode: "
+ Integer.toHexString(charPassword.hashCode()));
The output is:
Original char password value: password
Original char password hashCode: 7cc355be
Changed char password value: ********
Changed char password hashCode: 7cc355be
As we can see, after we tried to replace the content of original String, the value remains the same and hashCode() method didn’t return a different value in the same execution of the application, meaning that the original String stayed intact.
And for the char[] array, we were able to change the data in the same object.
3. We Can Accidentally Print Passwords
Another benefit of working with passwords in char[] array is the prevention of accidental logging of the password in consoles, monitors or other more or less insecure places.
Let’s check out the next code:
String passwordString = "password";
char[] passwordArray = new char[]{'p', 'a', 's', 's', 'w', 'o', 'r', 'd'};
System.out.println("Printing String password -> " + passwordString);
System.out.println("Printing char[] password -> " + passwordArray);
With the output:
Printing String password -> password
Printing char[] password -> [C@6e8cf4c6
We see that the content itself is printed in the first case, while in the second case, the data is not so useful, which makes char[] less vulnerable.
4. Conclusion
In this quick article, we emphasized several reasons why we shouldn’t use Strings for collecting passwords and why we should use char[] arrays instead.
As always, code snippets can be found over on GitHub.