3

I'm working on a Java service that had a security bug logged against it, concerning a secret stored in a Java String object.

The concern is that once a password is stored in a String, it stays in the string pool until it's garbage collected, and could show up in a dump as clear text.

I understand that Java's String class is immutable, and it is preferred that secrets or passwords be stored in a mutable class, so it can be removed from memory as soon as possible after use.

References

However, I find this impractical when working with 3rd party libraries, as many of them want the password or secret passed in the request as a String object, which no matter how safe I am, in my code, ultimately converts the char[] array into a String, which takes us back to the original problem, doesn't it?

So, is there anyway to convert a char[], or StringBuffer to a String, without getting back to the original problem?

EDIT: As pointed out by the comments in this question and other similar questions, many believe this is not a real concern, as there's no easy way to avoid the issue if you don't own ALL the code in your application (ie don't pass secrets to any 3rd party libraries). So given this, maybe the question becomes

How can I refute the bug? is there a good solid reference from Oracle/Owasp or whoever that says "unsolvable problem" ?

Brad Parks
  • 66,836
  • 64
  • 257
  • 336
  • 2
    There’s a `String` constructor that takes a `char[]` and `StringBuffer.toString` yields a string. But you could’ve found these out easily from Javadocs, so, I’m not sure if there’s another question that you meant to ask. If you’re using 3pp libraries that accept passwords as strings, there’s nothing you can do except use another library. – Abhijit Sarkar May 10 '23 at 15:37
  • 1
    @AbhijitSarkar The question wasn't how to convert, the question was how to convert w/o ending up in the same place. – Dave Newton May 10 '23 at 15:40
  • What is this “same place”? Is the question “how to convert to string without converting to string?” – Abhijit Sarkar May 10 '23 at 15:41
  • 3
    @AbhijitSarkar the question was how to avoid a password stored as String being possibly gc'd and showing up in a heap dump, which is a valid concern. to my knowledge tho, i don't think this is possible – 0x150 May 10 '23 at 15:44
  • @AbhijitSarkar It's unlikely you don't understand the question/concern. The last sentence of your comment is the correct answer and all that was necessary. – Dave Newton May 10 '23 at 15:46
  • 1
    The problem isn't the String object, it's the fact that there is a 'secret' or password in there! –  May 10 '23 at 15:48
  • read the password from os.environment instead of placing it hardcoded into your application if possible. and do not store it in a string, but read it from os.env like needed. also you might want other libraries – zeg May 10 '23 at 15:49
  • 1
    You could use reflection, e.g. `field = String.class.getDeclaredField("value"); field.setAccessible(true);` and then fill it with 0s, but to do that you have to relax the JVM security mechanisms to an extend that will make it more risky than if you just stored the password in the String. – k314159 May 10 '23 at 16:09
  • Only interned strings are in the string pool, and only string literals or strings explicitly interned with `String#intern()` are interned, so is this really a problem to focus on? – Mark Rotteveel May 10 '23 at 16:12

1 Answers1

5

You can't avoid creating a String if you need to call an API that requires a String. As long as you avoid string literals or explicitly interned strings, strings don't end up in the string pool.

This is also an impossible problem to solve. For example, if this is a password for a database connection pool, the password needs to be available for the lifetime of the program to be able to create new connections. And even if you could provide the password in some clearable way like a char[], CharBuffer, StringBuilder, etc., there is no guarantee that the API you're calling doesn't transform it to a string, or makes a copy, etc., etc.

Even using a char[] does not guarantee that you're able to correctly purge it from memory: Java garbage collectors can and will move objects around, so it is entirely possible that your password is still in memory at a previous location, even if you explicitly zeroed that char[].

If a threat actor has sufficient access to your system to inspect memory, make heapdumps, etc., you have bigger problems, and worrying about using a String vs char[] is just a waste of time, because that threat actor will have other means of finding your password, like finding configuration sources, modifying your program to record the password on a next run, etc.

To be clear, being able to quickly clear certain sensitive information can reduce the window of attack, but unless you're working in high-security environments, it is unlikely to be the right thing to focus on given all the caveats.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
  • yeah this is what I was trying to convey in the question - that no matter how careful I am with the secret, as soon as I pass it off to some 3rd party libary/code that I don't have control over, they could convert it to a String, and we're right back at the same place. So maybe the question becomes - how can I refute the bug? is there a good solid reference from Oracle/Owasp or whoever that says "unsolvable problem" ? – Brad Parks May 10 '23 at 16:37
  • 2
    @BradParks Not every security finding needs to be addressed. I’ve dealt with security audits several times, and it is their job to find out even the smallest possible loophole. Your job is to consider the surface area of the attack, the probability of the attack happening, and the effort needed to close the hole. – Abhijit Sarkar May 10 '23 at 17:00
  • The way it works at my job is there's a whole security team, that logs security bugs, and we basically have to address their requests, unless we can really refute them – Brad Parks May 10 '23 at 18:22
  • 2
    @BradParks Acknowledging the potential issue and accepting it because the risk is low or there are other controls in place, like restricting access using firewalls to prevent exploitation if the secret is exfiltrated, and explicitly documenting it, is usually also accepted by security auditor. – Mark Rotteveel May 11 '23 at 08:13