如何在Apache HttpClient中設定TLS版本

碼農熊貓發表於2021-07-20

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版本。

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

翻譯:碼農熊貓

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

相關文章