Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting Java system properties without putting the values on the command line

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.

like image 319
Tom Anderson Avatar asked Apr 19 '11 10:04

Tom Anderson


4 Answers

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.

like image 80
WhiteFang34 Avatar answered Sep 18 '22 00:09

WhiteFang34


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.

like image 23
David J. Liszewski Avatar answered Sep 22 '22 00:09

David J. Liszewski


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

like image 44
Bill Birch Avatar answered Sep 22 '22 00:09

Bill Birch


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(...){
    ...
    }
like image 42
michael.new Avatar answered Sep 18 '22 00:09

michael.new