Java,Apache HttpClient,TLSv1.2和OpenJDK 7

问题描述:

我们有一小组运行OpenJDK v1.7.0_111的Tomcat服务器。我们计划在今年夏季对它们进行升级和迁移,但我们发现我们与之交互的客户端API正在转向在短期内需要TLSv1.2。我的最终愿望是找到一个配置更改以实现此目的。Java,Apache HttpClient,TLSv1.2和OpenJDK 7

应用托管有创建它是在一个非常直接的方式SSL上下文:

SSLContext sslContext = SSLContexts.createDefault() 
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext); 

SSLContexts是Apache的HttpClient库(版本4.4.1),也是相当直截了当它是如何创建的SSL背景:

public static SSLContext createDefault() throws SSLInitializationException { 
    try { 
     SSLContext ex = SSLContext.getInstance("TLS"); 
     ex.init((KeyManager[])null, (TrustManager[])null, (SecureRandom)null); 
     return ex; 
    } catch (NoSuchAlgorithmException var1) { 
     throw new SSLInitializationException(var1.getMessage(), var1); 
    } catch (KeyManagementException var2) { 
     throw new SSLInitializationException(var2.getMessage(), var2); 
    } 
} 

并通过SSLConnectionSocketFactory类挖,似乎它只是使用SSLSocket.getEnabledProtocols()方法来确定哪些协议可用。请注意,在我的情况下,this.supportedProtocols为空。

public Socket createLayeredSocket(Socket socket, String target, int port, HttpContext context) throws IOException { 
     SSLSocket sslsock = (SSLSocket)this.socketfactory.createSocket(socket, target, port, true); 
     if(this.supportedProtocols != null) { 
      sslsock.setEnabledProtocols(this.supportedProtocols); 
     } else { 
      String[] allProtocols = sslsock.getEnabledProtocols(); 
      ArrayList enabledProtocols = new ArrayList(allProtocols.length); 
      String[] arr$ = allProtocols; 
      int len$ = allProtocols.length; 

      for(int i$ = 0; i$ < len$; ++i$) { 
       String protocol = arr$[i$]; 
       if(!protocol.startsWith("SSL")) { 
        enabledProtocols.add(protocol); 
       } 
      } 

      if(!enabledProtocols.isEmpty()) { 
       sslsock.setEnabledProtocols((String[])enabledProtocols.toArray(new String[enabledProtocols.size()])); 
      } 
     } 

我遇到的问题是,在运行一些初步测试,我不能让这些客户端连接到需要TLSv1.2工作的API。

在下面的示例中,我可以通过包含-Dhttps.protocols=TLSv1.2参数来完成URLConnection代码的完成,但我无法获得用于连接的Apache连接。

public static void main(String[] args) throws Exception{ 
     String testURL = "https://testapi.com"; 

     SSLContext sslcontext = SSLContext.getInstance("TLS"); 
     sslcontext.init(null, null, null); 

     try { 
      SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslcontext); 
      CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(socketFactory).build(); 

      HttpGet httpget = new HttpGet(testURL); 

      CloseableHttpResponse response = client.execute(httpget); 
      System.out.println("Response Code (Apache): " + response.getStatusLine().getStatusCode()); 
     } 
     catch (Exception e){ 
      System.err.println("Apache HTTP Client Failed"); 
      e.printStackTrace(); 
     } 

     try { 
      HttpsURLConnection urlConnection = (HttpsURLConnection) new URL(testURL).openConnection(); 
      urlConnection.setSSLSocketFactory(sslcontext.getSocketFactory()); 
      urlConnection.connect(); 
      System.out.println("Response Code (URLConnection): " + urlConnection.getResponseCode()); 
     } 
     catch (Exception e){ 
      System.err.println("HttpsURLConnection Failed"); 
      e.printStackTrace(); 
     } 

    } 

随着-Dhttps.protocols=TLSv1.2我已经试过了-Djdk.tls.client.protocols=TLSv1.2-Ddeployment.security.TLSv1.2=true JVM参数没有任何的运气。

有没有人有想过如何在此配置中启用TLSv1.2而无需升级到v8或将应用程序更改为专门请求TLSv1.2的实例?

+0

你试过这里显示HTTPS的PARAMS和测试: //blogs.oracle.com/java-platform-group/jdk-8-will-use-tls-12-as-default – pvg

+0

此外,您可能希望包含一个简短的[MCVE],以便JDK 7上的其他用户可以重现你正在尝试。 – pvg

+0

您不应启用所有支持的协议,因为它们包含不安全的匿名密码套件。 – EJP

jdk.tls.client.protocols只适用于您未使用的Java 8(可能是9)。

https.protocols只能在默认情况下在HttpsURLConnection httpclient不使用。

deployment.*仅适用于您未使用的JNLP和小程序(如果任何浏览器仍允许小程序)。

如说,至少4.5,假设你使用HttpClientBuilderHttpClients(你没有说)你Q上的答案,就是分别用.createSystem().useSystemProperties();这些做的使用与*URLConnection相同的系统属性 - 或者至少其中很多包括https.protocols。您应该检查此套件中包含的其他任何属性都已配置为执行您不想要的操作。这确实需要更改应用程序,但不是将它们更改为“专门请求... TLSv1.2”。

以外,你可以SSLConnectionSocketFactory配置指定允许在the Q linked by @pvg,或SSLContexts.custom().useProtocol(String).build()确切的协议指定上限 - 这是足以让你的情况,因为提供的范围“高达1.2”的服务器要求1.2会选择1.2。

+0

'jdk.tls.client.protocols'实际上应该在OpenJDK 7u91及更高版本和6u115及更高版本中可用,如果我了解[OpenJDK增强请求](https://bugs.openjdk.java.net/browse/JDK- 8076369)正确。 – russianmario

下面是配置Apache的HttpClient 4.x中使用特定的TLS/SSL版本

CloseableHttpClient client = HttpClientBuilder.create() 
    .setSSLSocketFactory(new SSLConnectionSocketFactory(SSLContext.getDefault(), new String[] { "TLSv1.2" }, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier())) 
    .build(); 

投票最多dave_thompson_085的答案被推荐的方式