ブラウザで正常に機能するサードパーティの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);
また、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();
または NoopHostnameVerifier も使用:
CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).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
使用している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を有効にします。
JVM引数:
-Dhttps.protocols=TLSv1.2,TLSv1.1,TLSv1
または、Javaコードから同じプロパティを設定します。
System.setProperty("https.protocols", "TLSv1.2,TLSv1.1,TLSv1");
または、 Java 7のJCE Unlimited Strengthポリシーファイルをインストールします 。 JVMが既存のアルゴリズムのより強力なバージョンを使用できるようにしながら、JCEをインストールすることは常に価値がありますが、この単一のステップで問題が解決するかどうかは100%わかりません。
注:オプション1と2でプロトコルの順序が改善されました(TLSバージョン1.2から1)。