如何在Apache HttpClient中設置TLS版本

1、簡介

Apache HttpClient是一個底層、輕量級的客戶端HTTP庫,用於與HTTP伺服器進行通訊。
在本教程中,我們將學習如何在使用HttpClient時配置支援的傳輸層安全(TLS)版本。
我們將首先概述TLS版本協商如何在客戶端和伺服器之間工作。
之後,我們將看看在使用HttpClient時配置支援的TLS版本的三種不同方式。

2、TLS版本協商

TLS是一種互聯網協議,可在兩方之間提供安全、可信的通訊。它封裝了像HTTP這樣的應用層協議。
TLS協議自1999年首次發布以來已多次修訂。
因此,客戶端和伺服器在建立新連接時,首先就他們將使用的TLS版本達成一致非常重要。
TLS版本在客戶端和伺服器交換hello消息後達成一致:

  1. 客戶端發送支援的 TLS 版本列表。
  2. 伺服器選擇一個並在響應中包含所選版本。
  3. 客戶端和伺服器使用所選版本繼續連接設置。

由於存在降級攻擊的風險,因此正確配置Web客戶端支援的TLS版本非常重要。
請注意,為了使用最新版本的TLS(TLS 1.3),我們必須使用Java 11或更高版本。

3、固定設置TLS版本

3.1、SSLConnectionSocketFactory

讓我們通過HttpClients#custom訂製構建方法提供的HttpClientBuilder,來訂製我們的HTTPClient配置。
此構建器模式允許我們傳入我們自己的SSLConnectionSocketFactory,它將根據一組所需支援的TLS版本進行實例化:

SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
  SSLContexts.createDefault(),
  new String[] { "TLSv1.2", "TLSv1.3" },
  null,
  SSLConnectionSocketFactory.getDefaultHostnameVerifier());

CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();

返回的Httpclient對象現在可以執行HTTP請求了。
通過在SSLConnectionSocketFactory構造函數中顯式設置支援的協議,客戶端將僅支援通過TLS 1.2或TLS 1.3的通訊。
請注意,在 Apache HttpClient 4.3 之前的版本中,該類稱為SSLSocketFactory。

3.2、Java運行時參數

另外,我們可以使用Java的https.protocols系統屬性配置支援的TLS版本。
此方法可以防止必須將值硬編碼到應用程式程式碼中。
相反,我們將配置HttpClient以在設置連接時使用該系統屬性。
HttpClient API提供了兩種方法來實現。第一個是通過HttpClients#createSystem:

CloseableHttpClient httpClient = HttpClients.createSystem();

如果需要更多的客戶端配置,我們可以使用builder方法代替:

CloseableHttpClient httpClient = HttpClients.custom().useSystemProperties().build();

這兩種方法都告訴HttpClient在連接配置期間使用系統屬性。
這允許我們在應用程式運行時使用命令行參數設置所需的TLS版本。例如:

$ java -Dhttps.protocols=TLSv1.1,TLSv1.2,TLSv1.3 -jar webClient.jar

4、動態設置TLS版本

還可以根據主機名和埠等連接詳細資訊設置TLS版本。我們將擴展SSLConnectionSocketFactory並覆蓋prepareSocket方法。
客戶端會在啟動新連接之前調用prepareSocket方法,這將可以讓我們在每個連接的基礎上決定使用哪些TLS協議。
也可以啟用對舊TLS版本的支援,但前提是遠程主機具有特定的子域:

SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(SSLContexts.createDefault()){

    @Override
    protected void prepareSocket(SSLSocket socket) {

        String hostname = socket.getInetAddress().getHostName();
        if (hostname.endsWith("internal.system.com")){
            socket.setEnabledProtocols(new String[] { "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3" });
        }
        else {
            socket.setEnabledProtocols(new String[] {"TLSv1.3"});
        }
    }
};
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();

在上面的示例中,prepareSocket方法首先獲取SSLSocket將連接到的遠程主機名,然後使用主機名來確定要啟用的TLS協議。
現在,我們的HTTP客戶端將對每個請求強制執行TLS 1.3,除了目標主機名的格式為*.internal.system.com。
由於能夠在創建新SSLSocket之前插入自定義邏輯,我們的應用程式現在可以自定義TLS通訊的詳細資訊。

5、結論

在本文中,我們研究了在使用Apache HttpClient庫時配置支援的TLS版本的三種不同方式。
我們已經了解了如何為所有連接或基於每個連接設置TLS版本。

原文://www.baeldung.com/apache-httpclient-tls

翻譯:碼農熊貓

更多技術乾貨,請訪問我的個人網站//pinmost.com,或關注公眾號【碼農熊貓】

Tags: