1. 序章

Apache HttpClientは、HTTPサーバーと通信するための低レベルで軽量のクライアント側HTTPライブラリです。 このチュートリアルでは、 HttpClient を使用するときに、サポートされているトランスポート層セキュリティ(TLS)バージョンを構成する方法を学習します。 まず、クライアントとサーバー間でTLSバージョンネゴシエーションがどのように機能するかについての概要から始めます。 その後、HttpClientを使用するときにサポートされるTLSバージョンを構成する3つの異なる方法を見ていきます。

2. TLSバージョンネゴシエーション

TLSは、2者間で安全で信頼できる通信を提供するインターネットプロトコルです。 HTTPなどのアプリケーション層プロトコルをカプセル化します。 TLSプロトコルは、1999年に最初に公開されて以来、何度か改訂されています。 したがって、クライアントとサーバーは、新しい接続を確立するときに使用するTLSのバージョンについて最初に合意することが重要です。クライアントとサーバーがhelloメッセージを交換した後、TLSバージョンについて合意します。

  1. クライアントは、サポートされているTLSバージョンのリストを送信します。
  2. サーバーは1つを選択し、選択したバージョンを応答に含めます。
  3. クライアントとサーバーは、選択したバージョンを使用して接続セットアップを続行します。

ダウングレード攻撃のリスクがあるため、サポートされているTLSバージョンのWebクライアントを正しく構成することが重要です。最新バージョンのTLS(TLS 1.3)を使用するには、次のことを行う必要があります。 Java11以降を使用します。

3. TLSバージョンを静的に設定する

3.1. SSLConnectionSocketFactory

HTTPClient 構成をカスタマイズするために、 HttpClients#customビルダーメソッドによって公開されるHttpClientBuilderを使用してみましょう。 このビルダーパターンを使用すると、独自の 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コンストラクターで明示的に設定することにより、クライアントはTLS1.2またはTLS1.3を介した通信のみをサポートします。 4.3より前のバージョンのApacheHttpClientでは、クラスはSSLSocketFactoryと呼ばれていたことに注意してください。

3.2. Javaランタイム引数

または、Javaの https.protocols システムプロパティを使用して、サポートされているTLSバージョンを構成することもできます。 この方法により、値をアプリケーションコードにハードコーディングする必要がなくなります。 代わりに、接続を設定するときにシステムプロパティを使用するようにHttpClientを構成します。 HttpClient APIは、これを行うための2つの方法を提供します。 1つ目は、 HttpClients#createSystem経由です。

CloseableHttpClient httpClient = HttpClients.createSystem();

より多くのクライアント構成が必要な場合は、代わりにビルダーメソッドを使用できます。

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"});
        }
    }
};<br />
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();

上記の例では、 prepareSocket メソッドは、最初にSSLSocketが接続するリモートホスト名を取得します。 次に、ホスト名を使用してTLSプロトコルで有効にするかどうかを決定します。これで、宛先ホスト名が* .internal.example.comの形式である場合を除き、HTTPクライアントはすべてのリクエストでTLS1.3を適用します。 。新しいSSLSocketを作成する前にカスタムロジックを挿入する機能により、アプリケーションはTLS通信の詳細をカスタマイズできるようになりました。

5. 結論

この記事では、ApacheHttpClientライブラリを使用するときにサポートされるTLSバージョンを構成する3つの異なる方法について説明しました。 TLSバージョンをすべての接続に対して、または接続ごとに設定する方法を見てきました。 この記事で使用されているコードサンプルは、GitHubから入手できます。