Перейти к основному содержимому

Как установить версию TLS в Apache HttpClient

· 4 мин. чтения

1. Введение

Apache HttpClient — это низкоуровневая облегченная клиентская HTTP-библиотека для связи с HTTP-серверами. В этом руководстве мы узнаем, как настроить поддерживаемые версии безопасности транспортного уровня (TLS) при использовании HttpClient . Мы начнем с обзора того, как работает согласование версии TLS между клиентом и сервером. После этого мы рассмотрим три различных способа настройки поддерживаемых версий TLS при использовании HttpClient .

2. Согласование версии TLS

TLS — это интернет-протокол, обеспечивающий безопасную и надежную связь между двумя сторонами. Он инкапсулирует протоколы прикладного уровня, такие как HTTP. Протокол TLS несколько раз пересматривался с момента его первой публикации в 1999 году. Поэтому важно, чтобы клиент и сервер сначала договорились о том, какую версию TLS они будут использовать при установлении нового соединения. Версия TLS согласовывается после обмена приветственными сообщениями между клиентом и сервером:

  1. Клиент отправляет список поддерживаемых версий TLS.
  2. Сервер выбирает один и включает выбранную версию в ответ.
  3. Клиент и сервер продолжают настройку соединения, используя выбранную версию.

Важно правильно настроить поддерживаемые версии TLS веб-клиента из-за риска атаки с понижением версии . Обратите внимание: чтобы использовать последнюю версию TLS (TLS 1.3), мы должны использовать Java 11 или более позднюю версию.

3. Статическая установка версии TLS

3.1. SSLConnectionSocketFactory

Давайте воспользуемся HttpClientBuilder , предоставляемым методом HttpClients#custom Builder, чтобы настроить нашу конфигурацию 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

Кроме того, мы можем настроить поддерживаемые версии TLS, используя системное свойство Java https.protocols . Этот метод избавляет от необходимости жестко записывать значения в код приложения. Вместо этого мы настроим HttpClient для использования системных свойств при настройке соединений. API HttpClient предоставляет два способа сделать это. Первый — через 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. Теперь наш HTTP-клиент будет применять TLS 1.3 при каждом запросе, за исключением случаев, когда имя хоста назначения имеет форму * .internal.example.com. Благодаря возможности вставлять пользовательскую логику перед созданием нового SSLSocket наше приложение теперь может настраивать детали связи TLS.

5. Вывод

В этой статье мы рассмотрели три разных способа настройки поддерживаемых версий TLS при использовании библиотеки Apache HttpClient. Мы видели, как можно установить версии TLS для всех соединений или для каждого соединения отдельно. Примеры кода, использованные в этой статье, доступны на GitHub .