Spring RestTemplate:SSL握手失败 [英] Spring RestTemplate: SSL handshake failure

查看:285
本文介绍了Spring RestTemplate:SSL握手失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用基本身份验证来获取宁静的ws.我没有将任何证书导入我的密钥库.当我使用chrome插件Advance Rest client进行测试时(使用基本身份验证和base64编码的用户名:pass).我可以看到回复.到目前为止,一切都很好. 但是,当我开发Java代码来消耗此ws时,会遇到SSL握手失败:

I am trying to consume a restful ws with basic auth. I did not import any cert into my keystore. When I use chrome plugin Advance Rest client to test it (using basic auth with base64 encoded username:pass). I can see the response back. So far so good. But when I develop Java code to consume this ws, I get SSL handsake failure:

org.springframework.web.client.ResourceAccessException: I/O error: 
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:453)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:401)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:377)
at test.Rest.main(Rest.java:37) Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at sun.security.ssl.Alerts.getSSLException(Unknown Source)
at sun.security.ssl.Alerts.getSSLException(Unknown Source)

我的问题是:如果问题是因为我没有将证书导入我的密钥库,那么Java代码和插件都不能一起工作.在这里,插件有效,但我的代码无效. 是什么原因?我的代码有问题吗?

My question is: if the problem is because I did not import cert to my keystore, then both Java code and plugin should not work together. Here, plugin works but my code does not. What is the reason? There is somethings wrong with my code?

以下是我的代码

RestTemplate restTemplate = new RestTemplate();         
 String plainCreds = "username:pass"; 
 byte[] plainCredsBytes = plainCreds.getBytes(Charset.forName("US-ASCII") );     
 byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes); 
 String base64Creds = new String(base64CredsBytes);

 HttpHeaders headers = new HttpHeaders(); 
 headers.add("Authorization", "Basic " + base64Creds);

 ResponseEntity<String> response =  
          restTemplate.exchange("https://url",HttpMethod.GET,new  
                                  HttpEntity(headers),String.class);

这是日志文件的链接:(我的服务器名称已由XXXXXX替换) http://www.filedropper.com/ssllog

Here is the link to log file:(I have replace my server-name by XXXXXX) http://www.filedropper.com/ssllog

运行后:openssl s_client -showcerts -tls1 -connect host:port

After running: openssl s_client -showcerts -tls1 -connect host:port

WARNING: can't open config file: /usr/local/ssl/openssl.cnf
CONNECTED(00000164)
8088:error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number:.\ssl\s3_pkt.c:362:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 5 bytes and written 0 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1
    Cipher    : 0000
    Session-ID:
    Session-ID-ctx:
    Master-Key:
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1452011344
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
---

这是我运行命令openssl s_client -connect server:port

and this is the output when i run command openssl s_client -connect server:port

WARNING: can't open config file: /usr/local/ssl/openssl.cnf
CONNECTED(00000164)
depth=0 C = US, ST = "XXXXXX", L = XXXXXX, O = XXXXXX, OU = xxxxx, CN = XXXXXXXXX.test.intranet, emailAddress = xxxxx@xxxxx
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 C = US, ST = "XXXXXXX ", L = XXXXX, O = XXXXXX, OU = xxxxxx, CN = XXXXXXXXX.test.intranet, emailAddress = xxxxx@xxxxx
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
 0 s:/C=US/ST=XXXXXXX /L=XXXXX/O=XXXXXX/OU=XXXXX/CN=XXXXXX.test.intranet/emailAddress=xxxxx@xxxxx
   i:/DC=intranet/DC=xxxx/CN=XXXXXX DEV Issuing CA
---
Server certificate
-----BEGIN CERTIFICATE-----
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXX.....
-----END CERTIFICATE-----
subject=/C=US/ST=XXXXXXX /L=XXXXX/O=XXXXXX/OU=XXXXX/CN=XXXXXX.test.intranet/emailAddress=xxxxx@xxxxx
issuer=/DC=intranet/DC=XXX/CN=XXXXX DEV Issuing CA
---
No client certificate CA names sent
Peer signing digest: SHA512
Server Temp Key: XXXXX, P-256, 256 bits
---
SSL handshake has read 1895 bytes and written 443 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES128-GCM-SHA256
    Session-ID: 568BF22A5CDBF103155264BBC056B272168AE0777CBC10F055705EB2DD907E5A
    Session-ID-ctx:
    Master-Key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1452012074
    Timeout   : 300 (sec)
    Verify return code: 21 (unable to verify the first certificate)
---
read:errno=0

推荐答案

javax.net.debug日志中,我可以看到您正在使用Java 7,并且客户端解析为TLSv1.从openssl输出中,您的服务器不支持TLSv1.

From javax.net.debug log I can see that you are using Java 7 and the client resolves to TLSv1. From openssl output that your server does not support TLSv1.

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 连接.

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. Some servers do not implement forward compatibility correctly and refuse to talk to TLS 1.1 or TLS 1.2 clients. For interoperability, SunJSSE does not enable TLS 1.1 or TLS 1.2 by default for client connections.

通过以下方式启用TLSv1.1和TLSv1.2:

Enable TLSv1.1 and TLSv1.2 either by:

  1. JVM参数:

  1. JVM argument:

-Dhttps.protocols=TLSv1.2,TLSv1.1,TLSv1

  • 或通过Java代码设置相同的属性:

  • Or set the same property from Java code:

    System.setProperty("https.protocols", "TLSv1.2,TLSv1.1,TLSv1");
    

  • 或安装 JCE Unlimited增强Java 7的策略文件.我不确定100%是否可以通过此步骤解决问题,尽管在让JVM使用更强大版本的现有算法的同时,始终值得安装JCE.

  • Or install JCE Unlimited Strength policy files for Java 7. 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.

    2016年9月29日更新:

    在选项1和2中,协议的顺序从好到坏(TLS版本1.2变为1).

    Order of protocols changed from better to worse (TLS ver. 1.2 to 1) in options 1 and 2.

    这篇关于Spring RestTemplate:SSL握手失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆