22

In Java the old way of storing a secret, such as a password, was to use char[] as you could overwrite its data when you were done with it. However this has since been shown to be insecure as the garbage collector will copy things around as it reorganizes the heap. On certain architectures it's possible that a page will be freed and the secret will remain when some other program allocates that same page.

This is horribly ugly, but what if the secret were stored on the stack of a Thread's run method? Care would still need to be taken to terminate the thread gracefully, so that it could zero out its data, but this problem was present in the old way as well.

One major problem I see straight away is that I can't think of a safe way to get data in and out of the container. You could minimize the likelihood of a leaked secret by using streams with very small internal buffers, but in the end you wind up with the same problem as char[]. [Edit: Would a single private static byte member and a flag work? Although that would limit you to one secret per ClassLoader. This adds more ugliness, but it might be easy enough to hide behind a well-written interface.]

So I have a bunch of questions, really.

Is the stack any more secure from these types of attacks than the heap? Are there any pure Java mechanisms to perform a stack-to-stack copy between two different stack frames in a manner that would be useful to this problem? If not, would the JVM even support this type of operation in bytecode?

[Edit: Before people worry too much, this is more of a thought experiment than anything else. I have absolutely no intention of 'testing in production' or using it in any current project. I realize that what I'm talking about is really ugly, probably horribly bulky, and works against the entire JVM structure. I'm just interested in whether it's possible, whether it actually accomplishes my goals, and what kinds of heroics it would take to make it happen.]

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
Ben Burns
  • 14,978
  • 4
  • 35
  • 56
  • 5
    If you're legitimately concerned about an attacker getting access to data like this, chances are you're screwed anyway, because any attacker sophisticated enough to be concerned about at this level is sophisticated enough to break most anything you can throw at them. – Dave Newton May 22 '13 at 16:41
  • In principle I agree, but that's a very poor argument for closing off a threat. Either way, I started down this path when reviewing a list of security requirements provided to me by my client. One is that we always zero out secrets in memory. Failure to do so will be caught by the client in review. The client is smart enough to understand that `char[]` won't work, however they also mandate that we use Java. Fortunately they are reasonable people, they recognize the conflict and it's not too big of a concern. But it got me to thinking... – Ben Burns May 22 '13 at 16:49
  • very poor argument against closing off a threat* - sorry, edit time period expired. – Ben Burns May 22 '13 at 18:00
  • 3
    Not really; there's an ROI for heroic protection efforts, and more often than not the R is dwarfed by the I. Not taking the ROI into account is foolish, and at this level, it's *critical*. Money and time are *perfectly* valid reasons to ignore specific kinds of threats under many (most) circumstances. We used to de-cap chips and swarm them with logic analyzers to capture essentially all system behavior (IP theft investigations)--if you're dealing with someone who can poke around at that level, you've most likely lost. – Dave Newton May 22 '13 at 18:10
  • 2
    Don't take this to mean it's not an *interesting* question, I just think that before you edited to explain it was an intellectual exercise, this level of hooping is almost *never* worth it. For security at this level, use specialized hardware. – Dave Newton May 22 '13 at 18:16
  • See, now I agree with that *totally*. Edit: That is, the ROI argument is far more valid than the assumption of sophistication argument. :-) – Ben Burns May 22 '13 at 18:16

1 Answers1

13

I would use a direct ByteBuffer. The memory this uses is not copied around and is only in one place for the life of the ByteBuffer. BTW don't use clear() as this just resets the position. You can overwrite it with

bb.clear();
while(bb.remaining() >= 8) bb.putLong(0);
while(bb.remaining() > 0) bb.put((byte) 0);

Is the stack any more secure from these types of attacks than the heap?

I wouldn't think so.

Are there any pure Java mechanisms to perform a stack-to-stack copy between two different stack frames in a manner that would be useful to this problem?

You could store the secret as one or two longs.

If not, would the JVM even support this type of operation in bytecode?

The byte code is designed to support Java and does very little more than what you can do in Java.

I'm just interested in whether it's possible, whether it actually accomplishes my goals, and what kinds of heroics it would take to make it happen

Use a direct ByteBuffer as I have suggested. ;)

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • "The memory this uses is not copied around..." - Doesn't it use a `byte[]` internally? That's stored on the heap and just as susceptible as any other array (like the `char[]` I mentioned above) to heap reorganization by the GC. – Ben Burns May 22 '13 at 16:52
  • 2
    A heap ByteBuffer uses a byte[], a direct ByteBuffer uses native memory. Native memory is not touched by the gc. – Peter Lawrey May 22 '13 at 16:55
  • I would ask is this more secure than storing in jvm memory? – ug_ May 22 '13 at 16:57
  • 1
    The contract specified by the class documentation is that the JVM *will attempt to avoid* copying the data to an intermediate buffer. – Andy Thomas May 22 '13 at 16:57
  • I would use the direct ByteBuffer as the only place it is stored, not an intermediate one. It has to be stored at least once. You could store it with a simple encryption so that just scanning the memory won't find it. – Peter Lawrey May 22 '13 at 17:02
  • 1
    Even in C you can't guarantee registers won't be written to memory. – Peter Lawrey May 22 '13 at 17:04
  • 1
    Nor guarantee that I won't just read your registers physically. – Dave Newton May 22 '13 at 18:10
  • Just read up on direct `ByteBuffer`, and I'm impressed. However, in the spirit of the original question, can you please elaborate on why you think the stack is just as bad as the heap? Since both BB and stack are off-heap, does BB have any security advantage aside from its obvious convenience? – Ben Burns May 22 '13 at 18:14