Setting Java system properties without putting the values on the command line
Asked Answered
C

6

6

I have some Java code which depends on a system property super.secret.password. I need to set that property when i run my app. The app will be started by a shell script, and the password will be kept in a file with minimal read permissions.

I really don't want to write:

java -Dsuper.secret.password=letmein gov.fortknox.MyApp

Because then anyone who can get on to the machine and run ps or top can see what the password is.

So, is there a good way to set system properties without exposing them on the command line?

The only generic solution we've come up with is to write a small C program which reads system properties from a file, then starts the JVM using the JNI invocation API. Needless to say, we are not keen to do this.

If there isn't a way to set them without using the command line, is there a way to hide the command line from prying eyes? We're using Red Hat Enterprise Linux Server 5.5.

For what it's worth, the app in question is actually JBoss EAP 4.3.0, and we're using the system properties to fill in substitution constructs (${like.this}) in its XML configuration files. There are JBoss-specific solutions - either use the SystemPropertiesService (by default, configured through the properties-service.xml file in the deploy directory) or pass the -P option to run.sh. However, i am interested in the more general case, where this could be any Java program.

Calzada answered 19/4, 2011 at 10:14 Comment(4)
I would have a property which says which file contains the password and give it appropriate read/write permissions.Lettie
@Peter: That would work if the consumer of the password was code i wrote myself. But in this case, it's being used by JBoss's templating mechanism (and another third-party templating mechanism, but that's less important). Is there a way to tell JBoss's templating mechanism to use, not a system property, but the contents of a file named in a system property? If not, then this doesn't solve the problem.Calzada
In that case, I would suggest instead that you restrict access to the box to those who are allowed to see the password. ;)Lettie
Perhaps i'll let you tell him that, because he's already quite a busy man!Calzada
U
3

You could just read the file somewhere near startup and call System.setProperty(). For a web application use a ServletContextListener so it happens early, see this answer for a quick example.

Update: this is perhaps not early enough for your use case with JBoss loading its configuration files.

Unbeaten answered 19/4, 2011 at 10:25 Comment(2)
In general, for code that's entirely under the programmer's control, this would be a good solution. But in the context of something like an app server, there's no way to inject the file-reading code near enough to startup. That's why i'm interested in a way to set the properties when i invoke java, rather than in code.Calzada
In the end, this is what we did. We subclassed a core component of JBoss which starts up very early, and did our property loading in its initialisation method. Not pretty, and Red Hat support would flip out if they saw it, but it works.Calzada
C
3

If your concern is exposing the value for super.secret.password in clear text but you are not worried about someone invoking your program with the correct value for the password because of you've covered that issue using permissions or some other means, then I think you could simply encrypt the password in your start-up script and have a wrapper class decrypt it.

java -Dsuper.secret.password=BbWvOuliHZVHVwsXudsj14d1iXzo655R gov.fortknox.DecryptWrapper

If the credentials are for a data source, I should also point out other solutions specific to JBoss: SecureIdentityLoginModule which essentially does the above, and PBEUtils which offers a keystore solution when used with SecureIdentityLoginModule. See EncryptingDataSourcePasswords.

And finally, the suggestion by Peter Lawery to use a file is valid too.

Cochabamba answered 19/4, 2011 at 10:54 Comment(2)
What would the DecryptWrapper class do?Calzada
There will actually be a few passwords: some for datasources, and some for web services. For datasources, the SecureIdentityLoginModule stuff looks very interesting - thanks. We might be able to find some way to use it for the web services too, where we have some of our own code in the path.Calzada
K
1

'cryptomainia' was written to solve this exact issue. It decrypts main() arguments. https://github.com/birchb1024/cryptomainia

Knowing answered 25/2, 2014 at 5:37 Comment(0)
N
1

You can read it from some file in a static initializer of your class that contains the main method:

    static {
        try {
          FileReader fr = new FileReader(FILE_NAME);
          // read the property
          System.setProperty(property.getName(), property.getValue());
        } catch (final FileNotFoundException ex) {
          logger.log(Level.SEVERE, ex.getMessage(), ex);
        } catch (final IOException ex) {
          logger.log(Level.SEVERE, ex.getMessage(), ex);
        }
    } 
    ...
    public static void main(...){
    ...
    }
Nathalia answered 26/1, 2015 at 12:24 Comment(0)
U
0

You can use JAVA_TOOL_OPTIONS environment variable and set the property there. But it will be visible still in your script file.

Underslung answered 19/4, 2011 at 10:22 Comment(3)
This is new to me. Based on a quick google, it looks like JAVA_TOOL_OPTIONS is used by JVMTI. Could you explain how you think this is helpful here?Calzada
Whatever is given in the JAVA_TOOL_OPTIONS environment variable is picked up as additional commandline arguments by java command.Underslung
My mistake. Got confused between JAVA_OPTS and JAVA_TOOL_OPTIONS. Both work the same way. JAVA_OPTS is only a convention and used by scripts. But JAVA_TOOL_OPTIONS is read by the JVM.Underslung
B
0

if an attacker has physical access to your machine, then there is no real reason why they can't own the machine - a simple rot13 to avert the casual eye is plenty.

If an attacker has some privileges (such as running top for example), but not physical access, then you can execute the program under a specialized user account (e.g., web-server-user), which has very little privilege, but has exclusive read access to a file containing the password. you then start up the app using that user account, and pass in the file path.

Doing so relies on the access privilege restrictions in the OS, which is likely to be implemented much better than what you can roll yourself.

Bolster answered 19/4, 2011 at 11:29 Comment(1)
Everything you write is true. But it doesn't answer the question, which is about how i set the system property so that some arbitrary code (in my case, JBoss) can read it.Calzada

© 2022 - 2024 — McMap. All rights reserved.