Java缓存SSL失败-我可以以某种方式清除这些错误

时间:2019-02-13 13:27:27

标签: java ssl

我正在尝试在单元测试中测试我的SSL实施,并且有一种我不太了解的情况。

当我一次连接到主机并失败时,随后的每个连接也会失败,即使它具有正确的证书也是如此。我假设在该方法的某个地方必须刷新缓存。

这是我的代码,服务器和客户端在本地运行。我将一个jks文件用于trustStore和keyStore。无论最初的错误是什么,都会发生错误,下次我总是会遇到第一个错误。

如果我不执行第一个请求,则第二个有效。

如果您想知道这里的用例是什么,我们有一些本地服务器使用来自内部PKI的https证书,当有人错误配置服务器或证书时,我们希望能够明显地更改它们,无需关闭整个虚拟机。

    //attempt a connection without certificates, will fail
    try (final InputStream stream = new URL("https://localhost:" + port).openStream()){
        System.out.println(IOUtils.toString(stream, Charset.defaultCharset()));
    } catch (IOException e){
        System.out.println("Failed to load: " + StackTraceUtil.getStackTrace(e));
    }

    //copies the jks file to a temporary location
    final File jksFile = copyJKSFile();

    //ignore host names, running locally, won't use this in production
    HttpsURLConnection.setDefaultHostnameVerifier((hostname, sslSession) -> hostname.equalsIgnoreCase("localhost"));

    //set the system properties
    System.setProperty("javax.net.ssl.keyStore", jksFile.getAbsolutePath());
    System.setProperty("javax.net.ssl.keyStorePassword", password);
    System.setProperty("javax.net.ssl.trustStore", jksFile.getAbsolutePath());
    System.setProperty("javax.net.ssl.trustStorePassword", password);

    //this should work now
    try (final InputStream stream = new URL("https://localhost:" + port).openStream()){
        System.out.println(IOUtils.toString(stream, Charset.defaultCharset()));
    } catch (IOException e){
        System.out.println("Failed to load: " + StackTraceUtil.getStackTrace(e));
    }

感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

所以我找到了一个解决方案,我想分享一下,以防别人在某个时候遇到这个问题。

javax.net.ssl.HttpsURLConnection使用javax.net.ssl.SSLSocketFactory来加载密钥和TrustStore,后者在内部使用javax.net.ssl.SSLContext。当您不覆盖任何内容时,它将使用默认实现,该实现将加载文件,并且一旦加载就无法重置。

所以我做的不是使用默认的实现,而是当我知道文件会更改时设置自己的SSLContext

final SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, null, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());

如果您想使用旧版TLS,则完整列表应为here