16

A common Java security guideline for handling sensitive data (== passwords) recommends never using a String object to store the data, and instead using an array of bytes or chars. I am trying to apply this guideline in a HttpServlet handler. In particular, I am using a basic-authentication-like approach where the credentials are passed in in a header (this is a GET request, so no body).

The issue I'm running into is that it seems impossible to get to the header data without generating a String object, which violates the guideline from the get-go. I've searched for a solution pretty thoroughly, and didn't find any relevant discussion. Does anybody have any insight into this issue?

NOTE: this takes place over HTTPS, so there is no connection security problem here.

Daniel S.
  • 3,494
  • 24
  • 30
  • Isnt everything 1s and 0s.. How is a string more of a security threat than a byte[] ? – smk Feb 22 '13 at 03:21
  • 3
    @smk: Because `String`s can be interned, which means they stick around in memory long after you've finished using them. – Cameron Skinner Feb 22 '13 at 03:25
  • 7
    @smk Strings are immutable. Once you have one, it's going to hang around in memory until it's garbage-collected (long after you're done with it). With a `byte[]`, once you're done with it, you can overwrite the contents to prevent the data from being read. – cheeken Feb 22 '13 at 03:25
  • 1
    @CameronSkinner It has nothing to do with interning (although that does exacerbate the problem). Even a String in heap space that has yet to be garbage collected is still available in its immutable entirety in memory. – Tim Pote Feb 22 '13 at 03:28
  • Thanks guys. This is why i love SO. – smk Feb 22 '13 at 03:37
  • Of course, a good optimizer can potentially notice that the array will never be read from again and get rid of the zeroing. The garbage collector can also move the memory backing an array around. `ByteBuffer.allocateDirect()` should be reasonably safe... – tc. Feb 22 '13 at 04:19
  • 1
    Maybe this concern has some validity on a client machine, but none on a server machine, where a lot more critical secrets are easily accessible. – irreputable Feb 22 '13 at 04:20
  • 1
    See http://stackoverflow.com/questions/8881291/why-is-char-preferred-over-string-for-passwords – Raedwald May 01 '15 at 19:06

1 Answers1

17

The simple answer is that you can't get the parameter in any other form than a String. At least, not using the standard servlet APIs. But there are a couple of possible "get outs".

  1. If you are prepared to get really ugly, you can in fact break the abstraction of the String object, and reach in and overwrite the characters. (Strings are in fact mutable if you are prepared to break the rules. This is one of the few situations where this might be justified.)

  2. There might be a nonstandard API extension in your web container's implementation of (say) HttpServletRequest for doing this. If not, you may be able to get hold of the source code and add one. (Assuming you are using an open-source web container.)


Having said that, IMO the "no strings" approach to Java security is misguided, or at least over-rated in terms of what it achieves.

The "no strings" approach guards against the possibility that something can trawl through the address space of your application, locate things that look like strings, and sniff out possible passwords. In theory, this could be done by:

  • a hacked (or vulnerable) Java application that breaks the JVM's execution model and looks at the raw memory,
  • attaching a Java debugger and trawling through the reachable objects,
  • using "/dev/mem" or similar to read process memory from the outside,
  • accessing the remains of a program's swap image on the hard drive, or
  • somehow causing it to core dump and reading the dump.

However, all but the first of these requires that the bad guy has already broken security on the system. And if the bad guy has done that there are other (probably simpler) ways to steal passwords from your program ... which the "no strings" approach won't prevent.

And if you are worried about a hack that exploits a Java security flaw to read raw memory, that flaw could probably used in other ways; e.g. to inject code to alter the way that the passwords are handled by the code.

So in summary, "no strings" is protecting against either really difficult hacks, or against cases where your security is already blown. IMO1, it is not worth the effort ... unless you are required to implement military grade security.


1 - See Why is char[] preferred over String for passwords? for other viewpoints.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • As far as #1 goes, does Java define what possible consequences there might occur there? Let's say there already exists an equal string in memory somewhere, for example as a key in a hashtable. Is Java implementation allowed to map both strings to the same "text backing store" in this case (sorry I don't know the precise Java terminology here)? If that is so, by explicitly clearing out the strings coming in with HTTP packets I could in fact be opening a vicious DOS security hole in my application. – Daniel S. Feb 22 '13 at 04:05
  • 1
    It could do that. But in practice, it will only do that if something calls `String.intern()` on BOTH of the strings. The other possibility is that the password string shares backing with a larger string; e.g. the string representing the header line. I would not expect either of these scenarios to be a problem. – Stephen C Feb 22 '13 at 06:48
  • Actually, there is another scenario. That is older JVMs where the implementation of `String` would share the `char[]` backing array between different strings in some situations. The implementation of String was rewritten in Java 1.7.0_u6 to fix this. (It was a source of memory leaks!) – Stephen C Jul 06 '17 at 03:51