2017-05-04 218 views
3

我們有一小組運行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

回答

3

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

0

下面是配置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的答案被推薦的方式