Hide JKS keystore / truststore password when running Java process

Matt picture Matt · Jul 23, 2013 · Viewed 12.9k times · Source

I have a number of Java applications which connect to other applications and services via connections secured with SSL. During development, I can specify the keystore/truststore to use and the password by using the JVM args:

-Djavax.net.ssl.trustStore=certificate.jks 
-Djavax.net.ssl.trustStorePassword=mypassword 
-Djavax.net.ssl.keyStore=certificate.jks 
-Djavax.net.ssl.keyStorePassword=mypassword 
-Djavax.net.ssl.keyStoreType=jks

This works perfectly. However, there is a requirement when going to production to hide the password, using JVM args means anyone who looks at the process list will be able to see the password in clear text.

Is there a simple way to get around this? I considered importing the certificates into the JRE's lib/security/cacerts file, but my understanding is that this will still require a password. One option would be to store the password, encrypted, in a file and then get the applications to read and decrypt on the fly, but this will involve changing and re-releasing all the applications (there are quite a few of them) so I would rather avoid this if at all possible. Does the javax.net.ssl library have any native built-in support for encrypted passwords (even if it's something as simple as just base64encoding, or anything that makes the passwords not-clear-text)?

Any suggestions much appreciated.

Answer

Bruno picture Bruno · Jul 23, 2013

Firstly, you could consider hiding the ps output from other users, see these questions:

Secondly, importing your certificates (assuming with private keys) into lib/security/cacerts would be pointless: it's the default truststore, but not the default keystore (for which there is no default value).

Thirdly, you can never really "encrypt" the password that's going to be used by your application (in a non-interactive mode). It has to be used, so if it was encrypted, its encryption key would need to be made available in clear at some point. Hence, it's a bit pointless.

Base 64 encoding, as you suggest, is just an encoding. Again, it's quite pointless since anyone can decode it (e.g. based64 -d). Some tools, like Jetty, can store the password in an obfuscated mode, but that's not much more resistant than base 64 encoding. It's useful if someone is looking over your shoulder, but that's it.

You could adapt your application to read the passwords from a file (in plain text or obfuscated). You would certainly need to make sure this file isn't readable by unauthorised parties.

What really matters is to make sure that the keystore file itself is protected from users who are not meant to read it. Its password is meant to protect the container in cases where it would be readable by others or when you want to protect access in interactive mode. Since you can't really avoid to use the password in clear on a machine in unattended mode, there's little point having a difficult password, rather it's more important to protect the file itself. (It's not clear whether your applications are interactive or not, but I guess few users should be expected to type -Djavax.net.ssl....=... interactively.)

If you can't adapt your code to read from a file, change your keystore and keys passwords to a password you don't mind disclosing like "ABCD", and make sure you protect read access from this keystore file: that's what really matters in the end. Reading the password itself from a secondary file is merely postponing the problem by one step, since the password file and the keystore file are likely to be stored next to one another (and copied together by an unauthorised party).