Java security: how to clear/zero-out memory associated with an object? (And/or ensure that is the only instance/copy of a particular variable)

Viewed 11555

I'm in a discussion at work over how to secure sensitive information (e.g. passwords) stored in a Java program. Per security requirements, memory containing sensitive information is cleared, e.g. by setting the values of the bytes to all zeroes. The concern is that an attacker can observe the memory associated with the application process, and so we want to limit as much as possible the window of time such sensitive information hangs around. Previously, projects involved C++, so a memset() sufficed.

(Incidentally, the use of memset() has been called into question because some compilers are known to optimize it's use out of the resulting binary based on the assumption that, since the memory is not used later, there is no need to zero it in the first place. This blurb is a disclaimer for those who Google for "memset" and "clear memory", etc).

Now we have on our hands a Java project being pressed against this requirement.

For Java objects, my understanding is that:

  • a nulled reference only changes the value of the reference; the memory on the heap for the object still contains data
  • an immutable object like String would not be able to have it's data modified (or at least not easily, within the confines of a VM with an appropriately enabled security manager)
  • the generational garbage collectors may make copies of objects all over the place (as noted here)

And for primitives, my understanding is that:

  • a primitive-type variable in a local method would get allocated on the stack, and:
  • when you change it's value, you modify it directly in memory (as opposed to using a reference to handle an object on the heap).
  • copies can/would be made "behind the scenes" in some situations, such as passing it as an argument into methods or boxing (auto- or not) creating instances of the wrappers which contain another primitive variable holding the same value.

My coworker claims that Java primitives are immutable and that there is documentation from both the NSA and Oracle regarding the lack of support in Java for this requirement.

My position is that primitives can (at least in some situations) be zeroed by setting the value to zero (or boolean to false), and the memory is cleared that way.

I'm trying to verify if there's language in the JLS or other "official" documentation about the required behavior of JVMs when it comes to memory management with respect to primitives. The closest I could find was a "Secure Coding Guidelines for the Java Programming Language" on Oracle's site which mentions clearing char arrays after use.

I'd quibble over definitions when my coworker called primitives immutable, but I'm pretty sure he meant "memory cannot be appropriately zeroed" - let's not worry about that. We did not discuss whether he meant final variables - from context we were talking in general.

Are there any definitive answers or references on this? I'd appreciate anything that could show me where I'm wrong or confirm that I'm right.

Edit: After further discussion, I've been able to clarify that my coworker was thinking of the primitive wrappers, not the primitives themselves. So we are left with the original problem of how to clear memory securely, preferably of objects. Also, to clarify, the sensitive information is not just passwords, but also things like IP addresses or encryption keys.

Are there any commercial JVMs which offer a feature like priority handling of certain objects? (I imagine this would actually violate the Java spec, but I thought I'd ask just in case I'm wrong.)

6 Answers

Just aside but some of environments the java core security libs use char[] so it can be zeroed. I imagine that you don't get a guarantee tho.

Had this topic recently.

From the requirement, that all sensitive data have controlled lifecycle naturally comes the Design Measure: Every object shall be a Destroyable

From this you see immediately, that Java is not designed for security.

Sol.1: What you can do is defining explicit destructors, as you suggested which overwrite used memory as for byte arrays:

public static void destroy(byte[] a)
{
    if (a != null)
    {
        Arrays.fill(a, (byte) 0);
    }
}

Sol.2 With this you soon get to the border of limited access to private class members. There is still a transient solution using Reflection, as for JPasswordField

public static void destroy(javax.swing.JPasswordField pwfd) throws DestroyFailedException
{
    try
    {
        if (pwfd == null)
        {
            return;
        }
        javax.swing.text.Document doc = pwfd.getDocument();
        Segment txt = new Segment();
        doc.getText(0, doc.getLength(), txt); // use the non-String API
        Field fd_array = Segment.class.getDeclaredField("array");
        fd_array.setAccessible(true);
        char[] sga = (char[]) fd_array.get(txt);
        fd_array.setAccessible(false);
        destroy(sga);
    }
    catch (Throwable th)
    {
        th.printStackTrace();
        throw new DestroyFailedException();
    }
}

This way you can clean up any object with sensitive data. Though, this solution is transient, as newer Java Runtimes warn about unauthorized Reflection Operations and future Runtimes, will even forbid them; so an unsecure Java Design will be protected in the name of security ;)

Sol.3: The long term solution will be to replicate parts of the Java Runtime with Destroyable-s or do sensitive parts entirely native modules (JNI), where you have additional platform specific options of memory protection.

So, in a current project I replaced BigInteger operations with native GMP, where you can overwrite memory mangement and assert, that every single byte is cleaned up. Next step would be authentication policies for each function ...

Related