Every example I see says to use a strong password but then they just slap it in the source code. That doens't seem quite right to me.
Is it possible to authenticate to the keystore as the current account so no passwords are involved?
If that's not possible, I have a requirement to not store passwords in source code, which is perfectly acceptable, but it seems like at some point a password needs to be a part of the equation, can someone point me to the most secure way to handle this?
I'm tempted to add the password as part of the build, but then I have a plaintext password on the build server, which almost seems roughly the same to me.
First, the general rule: If you ship software which, all by itself, is able to unlock some 'secure store' (so, without involvment of a server under your control or some other hardware under your control)... it is impossible to hide this information from the owner of the computer it runs on.
Example: Webbrowsers tend to have a feature to offer storing website passwords. These passwords are stored in files, and with the right tools you can open these files and see the passwords plain as day. There is no way to fix that with more software or more cryptographic algorithms. The only solution is to make the software incapable of unlocking said datastore, for example by requiring that the user enter a master password every time they wanna look into it, or putting some sort of secure enclave into the hardware and having THAT take care of the crypto. Java generally does not have the right libraries to interact with such hardware (apple's T2 is a very advanced take on this concept; TPM chips are a budget option).
So, once you're okay with that, you can still go: Okay, well, I do NOT want the authentication keys in the source code; in order to build a production distributable from the sources, the builder will have to supply it. To accomplish that:
(Assuming maven style project structure):
- Make file
src/main/resources/com/yourcompany/yourproject/keys/KeyFile.txt
and then update your .gitignore
file to ignore that, by putting /src/main/resources/com/yourcompany/yourproject/keys/KeyFile.txt
in there.
- Write the key in this file. Share this file with some secure means with all members of the project who should have it.
Write code: In src/main/java/com/yourcompany/yourproject/keys/ProjectKey.java
have a static method to retrieve the key. It would look something like this:
public final class ProjectKey {
/* prevent instantiation */ private ProjectKey(){}
private static final String PROJECT_KEY = loadKey();
public static String getKey () {
if (PROJECT_KEY != null) return PROJECT_KEY;
throw new IllegalStateException(
"Key file not present; find somebody with the file and place in: " +
"src/main/resources/java/com/yourcompany/yourproject/keys/KeyFile.txt");
}
private static String loadKey() {
InputStream in = ProjectKey.class.getResourceAsStream("KeyFile.txt");
try {
return in == null ? null : new Scanner(in, "UTF-8").next();
} finally {
if (in != null) in.close();
}
}
}
Make a dir in your project called 'keys' or whatnot. In your .gitignore file at the root, put the line /keys
in order to ensure these do not go into source control.
You'd have to mess around with some build tool plugins if you want builds to fail if the file is missing. Also, you'd have to update the scanner's delimiter if the 'key' contains any whitespace (I'm using scanner here as the fastest way to turn an inputstream into a complete string; if you have for example Guava, it has better calls to do that, and you should use those).