[英]handshake_failure in RestTemplate GET Request which works in browser
I'm failing to send simple GET request to 3rd party https URL which works fine in browser:我无法向第 3 方 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)
I try follow related answers , but I didn't find solution.我尝试关注相关答案,但没有找到解决方案。
There's no certificate and I'm using Java 8, tried solutions as adding -Djsse.enableSNIExtension=false -Dhttps.protocols=TLSv1.2,TLSv1.1,TLSv1
没有证书,我正在使用 Java 8,尝试添加
-Djsse.enableSNIExtension=false -Dhttps.protocols=TLSv1.2,TLSv1.1,TLSv1
的解决方案
Added same headers as browser sends ( Accept
and User-Agent
), but no luck添加了与浏览器发送相同的标题(
Accept
和User-Agent
),但没有运气
Code代码
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);
Also curl is working by putting full url, from verbose output it uses Server certificate with:此外,curl 正在通过将完整的 url 从冗长的 output 中放入其中使用服务器证书来工作:
SSL connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
Tried also with configuration skip SSL certificate verification with same output:还尝试使用相同的 output 进行配置跳过 SSL 证书验证:
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null)
Or also with NoopHostnameVerifier :或者也可以使用NoopHostnameVerifier :
CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).build();
CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).build(); HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); requestFactory.setHttpClient(httpClient);
requestFactory.setHttpClient(httpClient);
curl -v results Server certificate: 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
EDIT编辑
I added certificate to java as @Walk suggested :我按照@Walk 的建议将证书添加到 java :
sudo keytool -importcert -file filename.cer -alias randomaliasname -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit
Certificate was added to keystore证书已添加到密钥库
I see certificate loaded as in browser, it works in JMeter, but still failed with same error using restTemplate or apache HTTPClient.我看到证书在浏览器中加载,它在 JMeter 中工作,但使用 restTemplate 或 apache HTTPClient 仍然失败并出现同样的错误。
I'm using Java 8 update 151.我正在使用 Java 8 更新 151。
Tried solution from @rmunge answer to add BouncyCastleProvider, but still same error尝试从@rmunge 回答添加 BouncyCastleProvider 的解决方案,但仍然出现相同的错误
security.provider.6=org.bouncycastle.jce.provider.BouncyCastleProvider
The root cause is most likely missing support for latest EC-based cipher suites like TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
根本原因很可能是缺少对基于 EC 的最新密码套件的支持,例如
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
Elliptical Curve Cryptography (ECC) is implemented by the SunEC
provider.椭圆曲线密码术 (ECC) 由
SunEC
提供商实施。 To be fully functional the following is required:要完全发挥作用,需要以下条件:
If the native library is not available the provider still works but provides only a subset of ECC-based ciphers (see comments in source of SunEC.java ).如果本机库不可用,则提供程序仍然有效,但仅提供基于 ECC 的密码子集(请参阅SunEC.java源代码中的注释)。 It seems that some linux distributions explicitely removed the native library or disabled the provider by default (eg RedHat , Amazon Linux ).
似乎某些 linux 发行版在默认情况下明确删除了本机库或禁用了提供程序(例如RedHat 、 Amazon Linux )。 So if the library should not be part of your JRE, update to the latest package version or directly download and install latest OpenJDK 8 version - simply copying the native lib from the download could also be an option - see here for example.
因此,如果该库不应该是您的 JRE 的一部分,请更新到最新的 package 版本或直接下载并安装最新的 OpenJDK 8 版本 - 也可以选择从下载中复制本机库 - 例如,请参见此处。
Another option would be to use a third-party cryptography provider like Bouncy Castle which has its own Provider for ECC.另一种选择是使用第三方加密提供商,如 Bouncy Castle,它有自己的 ECC 提供商。 For instruction see this question and its accepted answer.
有关说明,请参阅此问题及其接受的答案。
Can you please specify which version of Java you are using... If Java 7 then this will do the job for you.....您能否指定您使用的是哪个版本的 Java... 如果 Java 7 那么这将为您完成工作.....
I can see that your client resolves to TLSv1.我可以看到您的客户端解析为 TLSv1。 From
openssl
output that your server does not support TLSv1.从
openssl
output 得知您的服务器不支持 TLSv1。
TLS ver. TLS 版本。 1.1 and 1.2 are disabled in Java 7 by default.
Java 7 中默认禁用 1.1 和 1.2。
Although SunJSSE in the Java SE 7 release supports TLS 1.1 and TLS 1.2, neither version is enabled by default for client connections.
尽管 Java SE 7 版本中的 SunJSSE 支持 TLS 1.1 和 TLS 1.2,但默认情况下这两个版本均未启用客户端连接。 Some servers do not implement forward compatibility correctly and refuse to talk to TLS 1.1 or TLS 1.2 clients.
一些服务器没有正确实现前向兼容性并拒绝与 TLS 1.1 或 TLS 1.2 客户端通信。 For interoperability, SunJSSE does not enable TLS 1.1 or TLS 1.2 by default for client connections.
对于互操作性,SunJSSE 默认情况下不为客户端连接启用 TLS 1.1 或 TLS 1.2。
Enable TLSv1.1 and TLSv1.2 either by:通过以下方式启用 TLSv1.1 和 TLSv1.2:
JVM argument: JVM 参数:
-Dhttps.protocols=TLSv1.2,TLSv1.1,TLSv1
Or set the same property from Java code:或者从 Java 代码中设置相同的属性:
System.setProperty("https.protocols", "TLSv1.2,TLSv1.1,TLSv1");
Or install JCE Unlimited Strength policy files for Java 7 .或者为 Java 7 安装 JCE Unlimited Strength 策略文件。 I am not 100% sure if this single step would solve the problem although it is always worth to install JCE while it allows JVM to use stronger versions of existing algorithms.
我不能 100% 确定这一步是否能解决问题,尽管安装 JCE 总是值得的,同时它允许 JVM 使用现有算法的更强大版本。
Note : Order of protocols changed from better to worse (TLS ver. 1.2 to 1) in options 1 and 2.注意:选项 1 和 2 中的协议顺序从好到坏(TLS 版本 1.2 到 1)发生了变化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.