Linux 设置 Java 系统属性而不将值放在命令行上

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5714812/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 03:43:02  来源:igfitidea点击:

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

javalinuxjbosssystem-properties

提问by Tom Anderson

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.

我有一些依赖于系统属性的 Java 代码super.secret.password。我需要在运行我的应用程序时设置该属性。该应用程序将由 shell 脚本启动,密码将保存在具有最小读取权限的文件中。

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 psor topcan see what the password is.

因为这样任何人都可以进入机器并运行pstop可以看到密码是什么。

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.

我们提出的唯一通用解决方案是编写一个小型 C 程序,该程序从文件中读取系统属性,然后使用JNI 调用 API启动 JVM 。不用说,我们并不热衷于这样做。

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.

如果不使用命令行就没有办法设置它们,有没有办法隐藏命令行不被窥探?我们使用的是 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 optionto run.sh. However, i am interested in the more general case, where this could be any Java program.

就其价值而言,有问题的应用程序实际上是 JBoss EAP 4.3.0,我们使用系统属性来填充${like.this}其 XML 配置文件中的替换结构 ( )。有特定于 JBoss 的解决方案 - 要么使用SystemPropertiesService(默认情况下,通过部署目录中的 properties-service.xml 文件配置)或将-P 选项传递给 run.sh。但是,我对更一般的情况感兴趣,这可以是任何 Java 程序。

回答by Dakshinamurthy Karra

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

您可以使用 JAVA_TOOL_OPTIONS 环境变量并在那里设置属性。但它仍然在您的脚本文件中可见。

回答by WhiteFang34

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

您可以在启动附近的某个地方读取文件并调用System.setProperty(). 对于 Web 应用程序,使用 aServletContextListener以便它尽早发生,请参阅此答案以获取快速示例。

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

更新:对于 JBoss 加载其配置文件的用例来说,这可能还不够早。

回答by David J. Liszewski

If your concern is exposing the value for super.secret.passwordin 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.

如果您担心super.secret.password以明文形式公开 for 的值,但您不担心有人使用正确的密码值调用您的程序,因为您已经使用权限或其他方式解决了该问题,那么我认为您可以简单地加密启动脚本中的密码并使用包装类对其进行解密。

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: SecureIdentityLoginModulewhich essentially does the above, and PBEUtilswhich offers a keystore solution when used with SecureIdentityLoginModule. See EncryptingDataSourcePasswords.

如果凭据用于数据源,我还应该指出其他特定于JBoss 的解决方案:SecureIdentityLoginModule它基本上完成了上述工作,并且PBEUtils在与SecureIdentityLoginModule. 请参阅EncryptingDataSourcePasswords

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

最后,Peter Lawery使用文件的建议也是有效的。

回答by Chii

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.

如果攻击者可以物理访问您的机器,那么他们就没有真正的理由不能拥有这台机器——一个简单的 rot13 来避免不经意的目光就足够了。

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.

如果攻击者有一些权限(例如运行 top),但没有物理访问权限,那么您可以在专门的用户帐户(例如 web-server-user)下执行程序,该帐户的权限很小,但具有独占权限对包含密码的文件的读取权限。然后使用该用户帐户启动应用程序,并传入文件路径。

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.

这样做依赖于操作系统中的访问权限限制,这可能比您自己滚动的更好。

回答by Bill Birch

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

编写“cryptomainia”就是为了解决这个确切的问题。它解密 main() 参数。https://github.com/birchb1024/cryptomainia

回答by user2038872

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

您可以从包含 main 方法的类的静态初始值设定项中的某个文件中读取它:

    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(...){
    ...
    }