Saturday, January 17, 2009

Java Security: Why Not To Use String Objects For Storing Secrets

I participated to an OWASP email thread regarding the security of storing passwords in a JAVA string object vs. a char array.

The initial assumption is that since java String objects are handled by the garbage collection differently than other objects such as for example a char array, storing such passwords in string objects might represent a risk.

The threat scenario is potentially of information disclosure since additional instances of secrets stored with JAVA Strings such as for example passwords, even when are zeroed programmately they might allow the original values recovered from a memory dump.

Therefore when choosing between two method calls:
public Connection createConnection(String userName, String password) throw JMSException
or
public Connection createConnection(String userName, char[] password) throws
JMSException

The latter passes the password as a char array and is more secure then the first that uses a string object. I'll articulate why herein:

Let’s analyze the assumption first and point out the main differences when using char[] vs. using Strings. I would like to cover here first some background (for the non-java experts, I do not consider one myself too so bear with me) and terminology

According to the JAVA both specification all data types, char and String included are objects and the instances in memory of such objects are handled by the JVM and the garbage collector outside the control of the coding logic (different from C/C++ where memory instances can be handled by the programmers)

There are differences thought, in what a programmer can do with JAVA Strings. For example the value of a JAVA String object cannot be changed after has been initialized. If you would like to change a value to a string you need to use StringBuffer. This property of JAVA Strings is loosely defined as Strings being "immutable"

I say, loosely defined because refers to value hold by the object not the instance in memory. I stumbled on this definition myself (thanks Rogan Dawes to fail my assumption and shed the light). I assumed this relates to change the value in memory (that in JAVA is never the case). Indeed there are different flavors of immutability best described by the article herein:

So let's assume immutability in the "strong" sense, that means locking down a piece of data in perpetuity, such as creating an immutable object instance that cannot be changed by any code.

A char array, comparing with a String is mutable because the value assigned to the element can be changed.

For example, in the case of a char array,

char[] str = {‘a’,’b’,’c’};

the following will change the values to 0

for ( int i=0; i< str.length; i++) { str[i] = 0; } In the case of a JAVA String since is immutable, the value cannot be changed. For example, when a new instance is created when changing from uppercase to lower case the contents of the object: String str = “ABC”; str.toLowerCase(); Another example, illustrates the difference when assigning a new value: String str = “Hello”; str=”Goodbye”; The first creates an instance of "Hello" when the second one creates another instance (invoking the constructor of the class) and therefore assigning an object reference to be stored in str. The same will happen when concatenating strings with the + operators such as: String str=”Hello”; str = str + “Dolly”; There is also an additional consideration….(thanks to Rogan Dawes again..)
When using String objects get internalized (saved in an internal cache), which means
that even when you set the variable to null, the actual String object
may never be garbage collected.

Now back to the CreateConnection API examples, passing a password as char array to the API is better because, values of the passwords can be zeroed after used (same for keys and other shared secrets or confidential information) and no extra instances of passwords are left in memory to be garbage collected or cached.

This is also what JAVA recommends such as when using password based encryption:

Therefore, if you need to store passwords, a good reference on how to do it securely using char array instead of Strings it is shown herein;

On the issue about clearing password contents and using char[] instead of strings there is also a thread from Sun Inc herein

Indeed, the use of char[] instead of String is a good idea for security to prevent information disclosure of passwords via memory data access such as in the case of an attack toward information stored in memory such as memory dump caused by a denial of service attack. When handling encryption keys, the requirement to zeroes them is also driven by key management compliance such as FIPS140.

Now, I am still puzzled about this because immutability of Strings was devised by Sun as part of the JAVA security model. In 2001 J Gosling the inventor of JAVA had to say this: (ref http://www.artima.com/intv/gosling313.html)

“One of the things that forced Strings to be immutable was security. You have a file open method. You pass a String to it. And then it's doing all kind of authentication checks before it gets around to doing the OS call. If you manage to do something that effectively mutated the String, after the security check and before the OS call, then boom, you're in. But Strings are immutable, so that kind of attack doesn't work. That precise example is what really demanded that Strings be immutable.”

But there are problems and assumptions. Even in this case the immutability of Strings does not offer security value 100%. See another thread herein
It is actually shown that char[] can be used as a way to write the contents of a String when untrusted code is allowed via the JVM. This is possible by using reflection and by depending on the results of SecurityManager. Because of this, someone also even argued that because of this Strings are not really immutable

Indeed in the summary, please do not use JAVA Strings and use char array instead when storing confidential data, credentials (e.g passwords) and secrets such as encryption keys…

2 comments:

Stanimir Simeonoff said...

The cited article of Sun is plain wrong and badly coded. For instance it doesn't do anything regarding the PushBackInputStream's buffer. Possibly it doesn't do anything for the InputStream's buffer and even less for the SSLEngine/Socket buffer. Zeroing memory sounds good on paper but it's almost impossible to implement either.

Java Strings just wrap a char[] and that's all about them, nothing special, unless they are intern()'d or are plain literals. In that case they are persistent in the memory. I can't imagine any sane operation involving intern() w/ password (or any security sensitive information), actually I know very few limited uses of intern() and most developers have never used it.

Using strings doesn't change much regarding the security. Like I've told I can't really grasp Sun's article idea about zeroing the memory the char[] holds. If the danger is some memory access, well the GC is free to move around (by copying) data and it's not necessary to zero anything afterwards. So the former location of the char[] holding the password will keep holding it until overriden. No difference with Strings.

Tilman Hausherr said...

I doubt that the "don't use strings for passwords" rule can be used for servlets, especially JSF-based servlets, because strings are used internally to pass the input to the backing bean.