Spring RestTemplate : SSL handshake failure

标签 spring authentication ssl basic-authentication resttemplate

我正在尝试使用具有基本身份验证的 restful ws。我没有将任何证书导入我的 keystore 。当我使用 chrome 插件 Advance Rest client 对其进行测试时(使用基本身份验证和 base64 编码的用户名:密码)。我可以看到回复。到目前为止,一切都很好。 但是当我开发 Java 代码来使用这个 ws 时,我得到 SSL 握手失败:

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)

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

下面是我的代码

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

运行后: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 时的输出

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。

TLS ver. 1.1 and 1.2 are disabled in Java 7 by default.

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:

  1. JVM 参数:

    -Dhttps.protocols=TLSv1.2,TLSv1.1,TLSv1
    
  2. 或者通过 Java 代码设置相同的属性:

    System.setProperty("https.protocols", "TLSv1.2,TLSv1.1,TLSv1");
    
  3. 或安装JCE Unlimited Strength policy files for Java 7 .我不能 100% 确定这一步是否能解决问题,尽管安装 JCE 总是值得的,因为它允许 JVM 使用现有算法的更强版本。

2016 年 9 月 29 日更新:

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

关于 Spring RestTemplate : SSL handshake failure,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34563385/

相关文章:

java - 使用 Spring Security 成功登录后服务器连接丢失

windows - 鱿鱼透明+ HTTPS

java - JmsOutboundGateway - Java 配置缺少选项?

spring - 使用 MvcUriComponentsBuilder::fromMethodCall 并将 String 作为返回类型

php - Symfony:多个防火墙上下文 - 用户被转发到错误的上下文

java - 使用 Apache HttpClient 通过 SSL 身份验证发送 HTTP 请求

java - 即使我提到了 mainClass 属性并且它就在它的 Nose 底下,Spring-boot maven 插件也无法找到 mainClass

java - 在 Controller 、spring 内部的 @postconstruct 方法中实例化 @autowired bean

ssl - 带有内部 DNS 的 SAN 证书

ssl - 将 SSL 证书更改到其他位置