对于授权服务,我是否应该始终在WebClient中明确加载keyStore



我有一个java密钥库,可以用它连接到受保护的https第三方服务。当我初始化我的web客户端时,我在代码中明确使用了这个密钥库:

// Solution #1
String password = "changeit";
KeyStore keyStore = KeyStore.getInstance(new File("src/main/resources/keystore.jks"), password.toCharArray());
SSLContext sslContext = new SSLContextBuilder()
.loadKeyMaterial(keyStore, password.toCharArray())
.build();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext, (hostname, session) -> true);
HttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(socketFactory)
.build();

有了这种方法,一切都很好。

但我也知道,有可能指定系统变量javax.net.ssl.keyStorejavax.net.ssl.keyStorePassword。所以我期待着上面代码的替代解决方案也能起作用:

// Solution #2
System.setProperty( "javax.net.ssl.keyStore", "src/main/resources/keystore.jks");
System.setProperty( "javax.net.ssl.keyStorePassword", "changeit"); 
HttpClient httpClient = HttpClients.createDefault();

在这里,我创建了一个默认的web客户端,而不显式地使用密钥库构建SSLContext。我预计默认的web客户端会以某种方式自动从javax.net.ssl.keyStore获取密钥库。但它似乎没有采取,这个解决方案没有为我工作。

所以我想知道使用系统属性javax.net.ssl.keyStore的目的是什么?它如何有用?这里的最佳做法是什么?

您可以执行与第一个解决方案类似的操作,但必须将密码作为String删除,密码应该在运行时加载的properties文件中,或者在启动JVM时将其指定为环境变量。

我想说的是,重点是密码不应该在代码中。

对于第二个解决方案,您可能需要检查trustStore环境变量。

https://docs.oracle.com/javadb/10.8.3.0/adminguide/cadminsslserver.html

为要提供给外部服务的公共证书设置信任库javax.net.ssl.trustStorejavax.net.ssl.keyStore用于在https上运行时存储您的私有证书。

// Your private cert location
System.setProperty("javax.net.ssl.keyStoreType", "pkcs12");
System.setProperty("javax.net.ssl.keyStore", env.getProperty(SSL_KEYSTORE));
System.setProperty("javax.net.ssl.keyStorePassword", env.getProperty(SSL_KEYSTORE_PASS));
// Public cert location
System.setProperty("javax.net.ssl.trustStoreType", "pkcs12");
System.setProperty("javax.net.ssl.trustStore", env.getProperty(SSL_TRUSTSTORE));
System.setProperty("javax.net.ssl.trustStorePassword", env.getProperty(SSL_TRUSTSTORE_PASS));

此外,我建议从一个单独的属性文件加载属性(尤其是密码(,正如Léo Schneider所提到的。

UPDATE对于您关于javax.net.ssl属性有用性的问题,这些属性是定义信任库和密钥库属性的替代方案。b/c是有用的,并非所有库都允许SSLContext作为可能需要的输入(例如不支持ssl的遗留库(。此外,还可以直接从命令行定义这些属性,从而提高可用性。

根据@Bruno在《如何访问jvm默认KeyStore?java中没有默认的CCD_ 11。这意味着,如果你使用运行应用程序

-Djavax.net.ssl.keyStorePassword=changeit -Djavax.net.ssl.keyStore=/opt/app/certificates/keyStore.jks

这也需要像一样在代码中解析它们

private static final String filePath = System.getProperty("javax.net.ssl.keyStore");
private static final String password = System.getProperty("javax.net.ssl.keyStorePassword");

然后在HttpClient中显式使用(类似于Solution #1(。换句话说,如果您不手动解析keyStore的属性,也不将其用于HttpClient,那么仅为其指定属性是没有用的。这是我发布问题时试图理解的。

这与类似TrustStore的的系统特性有重要区别

-Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStore=/opt/app/certificates/cacert

指定这些属性不需要任何额外的代码。因为有一个默认的TustStore,它将由JVM从属性中自动创建。然后的httpClient将只使用默认的TrustStore,而不需要开发人员付出任何努力。

最新更新