handshake_failure в запросе RestTemplate GET, который работает в браузере - PullRequest
3 голосов
/ 26 мая 2020

Мне не удается отправить простой запрос GET на сторонний https-URL, который отлично работает в браузере:

org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://...": Received fatal alert: handshake_failure; nested exception is javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:673)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:635)
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:556)

Я пытаюсь следовать связанным ответам , но я не нашел решение.

Сертификата нет, и я использую Java 8, пробные решения как добавление -Djsse.enableSNIExtension=false -Dhttps.protocols=TLSv1.2,TLSv1.1,TLSv1

Добавлены те же заголовки, что и браузер отправляет (Accept и User-Agent), но не повезло

Код

UriBuilder uriBuilder = UriBuilder.fromUri(URLDecoder.decode(URL, "UTF-8"));
HttpHeaders headers = new HttpHeaders();
headers.add("Accept", "text/html,application/xhtml+xml,application/xml");
headers.add(HttpHeaders.USER_AGENT, "Mozilla...");
HttpEntity<?> entity = new HttpEntity<Object>(headers);
ResponseEntity<ResponseVO> response = restTemplate.exchange(uriBuilder.build(), 
       HttpMethod.GET, entity, ResponseVO.class);
  • Сайт использует сервисы cloudflare

Также curl работает, помещая полный URL-адрес, из подробного вывода он использует сервер сертификат с:

SSL connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

Пробовал также с конфигурацией пропустить проверку сертификата SSL с тем же выводом:

TrustStrategy acceptTrustStrategy = (X509Certificate [] цепочка, String authType ) -> true;

SSLContext sslContext = org. apache .http.ssl.SSLContexts.custom () .loadTrustMaterial (null, acceptTrustStrategy) .build ();

Или также с NoopHostnameVerifier :

Closeabl eHttpClient httpClient = HttpClients.custom () .setSSLHostnameVerifier (новый NoopHostnameVerifier ()) .build (); HttpComponentsClientHttpRequestFactory requestFactory = новый HttpComponentsClientHttpRequestFactory (); requestFactory.setHttpClient (httpClient);

curl -v results Сертификат сервера:

*       subject: CN=*.site.com,OU=Domain Control Validated
*       start date: May 24 08:13:23 2019 GMT
*       expire date: May 24 08:13:23 2021 GMT
*       common name: *.site.com
*       issuer: CN=Go Daddy Secure Certificate Authority - G2,OU=http://certs.godaddy.com/repository/,O="GoDaddy.com, Inc.",L=Scottsdale,ST=Arizona,C=US

EDIT

Я добавил сертификат в java as @ Walk предложено :

sudo keytool -importcert -file filename.cer -alias randomaliasname -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit 

Сертификат был добавлен в хранилище ключей

Я вижу сертификат, загруженный как в браузере, он работает в JMeter, но все равно не удалось с той же ошибкой при использовании restTemplate или apache HTTPClient.

Я использую Java 8 update 151.

Пробовал решение от @rmunge ответ на добавление BouncyCastleProvider, но все та же ошибка

security.provider.6=org.bouncycastle.jce.provider.BouncyCastleProvider

Ответы [ 2 ]

2 голосов
/ 04 июня 2020

Причиной root, скорее всего, является отсутствие поддержки последних наборов шифров на основе E C, таких как TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

Криптография на основе эллиптических кривых (E CC) реализована поставщиком SunEC . Для полной работоспособности требуется следующее:

  • SunE C должен быть указан в jre / lib / security / java .security, а значение jdk.tls.disabledAlgorithms не должно содержать ECDHE
  • Собственная библиотека libsunce.so / sunce.dll должна быть доступна в папке jre / lib (Linux, Ma c) или jre / bin (Windows)
  • Убедитесь, что структура JDK JCE использует неограниченную политику. Поскольку Java 8u161 это новое значение по умолчанию, для более старых версий вам может потребоваться установить файлы политики юрисдикции JCE Unlimited Strength и / или внести изменения в файл java .security. См. здесь для дальнейших инструкций.

Если собственная библиотека недоступна, поставщик все еще работает, но предоставляет только подмножество шифров на основе E CC (см. Комментарии в источнике из SunE C. java). Похоже, что в некоторых linux дистрибутивах явно удалена собственная библиотека или отключен поставщик по умолчанию (например, RedHat , Amazon Linux). Поэтому, если библиотека не должна быть частью вашей JRE, обновите ее до последней версии пакета или напрямую загрузите и установите последнюю версию OpenJDK 8 - простое копирование собственной библиотеки из загружаемой также может быть вариантом - см. здесь например.

Другой вариант - использовать стороннего поставщика криптографии, такого как Bouncy Castle, у которого есть собственный поставщик для E CC. Для получения инструкций см. этот вопрос и принятый ответ на него.

1 голос
/ 08 июня 2020

Не могли бы вы указать, какую версию Java вы используете !!! Если Java 7, то это сработает за вас .....

Я вижу, что ваш клиент разрешает TLSv1. Из openssl выведите, что ваш сервер не поддерживает TLSv1.

TLS ver. 1.1 и 1.2 по умолчанию отключены в Java 7.

Хотя SunJSSE в выпуске Java SE 7 поддерживает TLS 1.1 и TLS 1.2, ни одна из версий не включена по умолчанию для клиента соединения. Некоторые серверы неправильно реализуют прямую совместимость и отказываются взаимодействовать с клиентами TLS 1.1 или TLS 1.2. Для обеспечения совместимости SunJSSE не включает TLS 1.1 или TLS 1.2 по умолчанию для клиентских подключений.

Включите TLSv1.1 и TLSv1.2 одним из следующих способов:

  1. Аргумент JVM:

    -Dhttps.protocols=TLSv1.2,TLSv1.1,TLSv1
    
  2. Или установите то же свойство из Java code:

    System.setProperty("https.protocols", "TLSv1.2,TLSv1.1,TLSv1");
    
  3. Или установите JCE Файлы политики неограниченной силы для Java 7 . Я не на 100% уверен, что этот единственный шаг решит проблему, хотя всегда стоит установить JCE, поскольку он позволяет JVM использовать более сильные версии существующих алгоритмов.

Примечание : Порядок протоколов изменен с лучшего на худший (TLS версии 1.2 на 1) в вариантах 1 и 2.

...