web-dev-qa-db-ja.com

ブラウザで機能するRestTemplate GETリクエストのhandshake_failure

ブラウザで正常に機能するサードパーティのhttps URLに単純なGETリクエストを送信できません。

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 acceptingTrustStrategy =(X509Certificate [] chain、String authType)-> true;

SSLContext sslContext = org.Apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null、acceptingTrustStrategy).build();

または NoopH​​ostnameVerifier も使用:

CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopH​​ostnameVerifier()).build(); HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); requestFactory.setHttpClient(httpClient);

curl -v結果サーバー証明書:

*       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

[〜#〜]編集[〜#〜]

証明書をJava @ 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を使用しています。

BormyCastleProviderを追加するために solution @rmungeの回答を試しましたが、同じエラーが発生します

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

使用しているJavaのバージョンを指定していただけますか!!! Java 7の場合、これでうまくいきます。

クライアントがTLSv1に解決されることがわかります。サーバーがTLSv1をサポートしていないというopenssl出力から。

TLSバージョンJava 7では、デフォルトで1.1と1.2が無効になっています。

Java SE 7リリースのSunJSSEは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コードから同じプロパティを設定します。

    System.setProperty("https.protocols", "TLSv1.2,TLSv1.1,TLSv1");
    
  3. または、 Java 7のJCE Unlimited Strengthポリシーファイルをインストールします 。 JVMが既存のアルゴリズムのより強力なバージョンを使用できるようにしながら、JCEをインストールすることは常に価値がありますが、この単一のステップで問題が解決するかどうかは100%わかりません。

:オプション1と2でプロトコルの順序が改善されました(TLSバージョン1.2から1)。

1
Kunal Vohra