我正在尝试使用基本身份验证来消耗一个宁静的ws。我没有将任何证书导入我的密钥库。当我使用chrome plugin Advance Rest client
来测试它时(使用带有base64编码的用户名:pass的基本auth)。我可以看到回复。到现在为止还挺好。
但是当我开发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)
我的问题是:如果问题是因为我没有将证书导入我的密钥库,那么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
答案 0 :(得分:7)
从javax.net.debug
日志我可以看到您正在使用Java 7,并且客户端解析为TLSv1。从openssl
输出,您的服务器不支持TLSv1。
TLS ver. 1.1 and 1.2 are disabled in Java 7 by default.
虽然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");
或安装JCE Unlimited Strength policy files for Java 7。我不是100%确定这一步是否能解决问题,尽管安装JCE总是值得的,同时它允许JVM使用更强版本的现有算法。
2016年9月29日更新:
在选项1和2中,协议的顺序从更好到更差(TLS版本1.2到1)。
答案 1 :(得分:1)
如果您碰巧使用Java 7,则需要明确告诉Java使用TLSv1.2协议。以下是使用Spring XML配置的示例。
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\n \"query\": [\n {\n \"code\": \"series1\",\n \"selection\": {\n \"filter\": \"item\",\n \"values\": [\n \"1\",\n \"2\",\n \"3\"\n ]\n }\n },\n {\n \"code\": \"series2\",\n \"selection\": {\n \"filter\": \"item\",\n \"values\": [\n \"1\",\n \"2\",\n \"3\"\n ]\n }\n }\n ],\n \"response\": {\n \"format\": \"json\"\n }\n}\n\n}");
你可以在没有XML的情况下做同样的事情:
***In any Spring bean (i.e. a controller)***
import org.apache.http.client.HttpClient;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClients;
import javax.net.ssl.SSLContext;
@Bean(name="client")
public HttpClient make() throws NoSuchAlgorithmException, KeyManagementException {
SSLContext sslContext = SSLContexts.custom().build();
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext,
new String[]{"TLSv1.2", "TLSv1.1"}, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier());
return HttpClients.custom()
.setSSLSocketFactory(sslConnectionSocketFactory)
.build();
}
***In XML configuration files***
<bean id="factory"
class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<property name="httpClient" ref="client"/>
</bean>
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="requestFactory" ref="factory"/>
</bean>