Java 接收 SSLHandshakeException:handshake_failure 尽管我的客户端忽略了所有证书
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9828414/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Receiving SSLHandshakeException: handshake_failure despite my client ignoring all certs
提问by Rsaesha
I have a Java program that connects to a webserver using SSL/TLS, and sends various HTTP requests over that connection. The server is localhost and is using a self-signed cert, but my code is using custom TrustManagers, and ignores invalid certificates. It has worked perfectly until now.
我有一个 Java 程序,它使用 SSL/TLS 连接到网络服务器,并通过该连接发送各种 HTTP 请求。服务器是 localhost 并且使用自签名证书,但我的代码使用自定义 TrustManagers,并忽略无效证书。到目前为止,它一直运行良好。
The only difference on the server is that it used to run jboss 6 and is now running jboss 7. I'm not sure if this is a configuration issue, or whether there is a problem with my code, but I get the same errors if I try to connect using other Java-based programs like WebScarab or ZAP.
服务器上的唯一区别是它以前运行 jboss 6,现在运行 jboss 7。我不确定这是配置问题,还是我的代码有问题,但如果出现相同的错误我尝试使用其他基于 Java 的程序(如 WebScarab 或 ZAP)进行连接。
In any case, is there anything I can do to my code to get around this problem? Here is the error in full:
无论如何,我可以对我的代码做些什么来解决这个问题?这是完整的错误:
Received fatal alert: handshake_failure
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(Unknown Source)
Here are the debug messages before the failure:
以下是失败前的调试消息:
main, WRITE: TLSv1 Handshake, length = 75
main, WRITE: SSLv2 client hello message, length = 101
main, READ: TLSv1 Alert, length = 2
main, RECV TLSv1 ALERT: fatal, handshake_failure
采纳答案by Rsaesha
So I found the problem. There might be a bug in Java, but the client seems to initiate a TLSv1 Handshake, but then sends an SSLv2 client hello message, at which point the server rejects the connection.
所以我发现了问题。Java 中可能存在错误,但客户端似乎发起了 TLSv1 握手,但随后发送了 SSLv2 客户端 hello 消息,此时服务器拒绝连接。
This happens even if you create your SSLContext with an instance of TLS:
即使您使用 TLS 实例创建 SSLContext,也会发生这种情况:
SSLContext sslContext = SSLContext.getInstance("TLS");
The solution is to set a system property before any connection attempts are made:
解决方案是在进行任何连接尝试之前设置系统属性:
System.setProperty("https.protocols", "TLSv1");
There are probably other solutions to it, but this one worked for me.
可能还有其他解决方案,但这个对我有用。
回答by uaarkoti
You are seeing this error most probably because the keystore that your JBoss 6 had access to is not accessible to your JBoss 7 instance.
您看到此错误很可能是因为 JBoss 6 有权访问的密钥库无法被 JBoss 7 实例访问。
What I would recommend is the following.
我要推荐的是以下内容。
Your self-signed server certificate must be imported into a truststore
您的自签名服务器证书必须导入信任库
keytool -import -alias gridserver -file server.crt -storepass $YOUR_PASSWORD_HERE -keystore server.keystore
Add the following properties to your run.conf
将以下属性添加到您的 run.conf
-Djavax.net.ssl.keyStoreType=pkcs12
-Djavax.net.ssl.trustStoreType=jks
-Djavax.net.ssl.keyStore=clientcertificate.p12
-Djavax.net.ssl.trustStore=server.keystore
-Djavax.net.debug=ssl # very verbose debug. Turn this off after everything looks good.
-Djavax.net.ssl.keyStorePassword=$YOUR_PASSWORD_HERE
-Djavax.net.ssl.trustStorePassword=$YOUR_PASSWORD_HERE
回答by Cratylus
The info you provide is very little as well as your stack trace.
I'll take a guess here.
What I suspect is that in the new server the protocol is TLSv1 while your clients try to connect with SSLv3 (or less) and as a result the handshake fails.
您提供的信息和堆栈跟踪信息都非常少。
我在这里猜一猜。
我怀疑在新服务器中,协议是 TLSv1,而您的客户端尝试使用 SSLv3(或更少)连接,结果握手失败。
Change you clients to use higher version of TLS
or
Make your webserver support SSLv3 as well. I know how to do this in Tomcat but not in JBoss.
将您的客户端更改为使用更高版本的 TLS 或
使您的网络服务器也支持 SSLv3。我知道如何在 Tomcat 中执行此操作,但在 JBoss 中不知道。
If this doesn't work update the post with more info (and a full stack trace).
You should enable ssl debug info -Djavax.net.debug=ssl
如果这不起作用,请使用更多信息(和完整的堆栈跟踪)更新帖子。
您应该启用 ssl 调试信息-Djavax.net.debug=ssl
回答by Bruno Grieder
The stack trace is from you client code and your client 'Received [a] fatal alert'. In other words, the SSL error happened in Jboss, not your client.
堆栈跟踪来自您的客户端代码和您的客户端“收到 [a] 致命警报”。换句话说,SSL 错误发生在 Jboss 中,而不是您的客户端。
Your client side custom TrustManagers have therefore nothing to do with it. My wild guess is that your new Jboss 7 is configured to require client certificate and your client did not present any.
因此,您的客户端自定义 TrustManager 与此无关。我的猜测是,您的新 Jboss 7 配置为需要客户端证书,而您的客户端没有提供任何证书。
To debug your SSL connection, use openssl and try this:
要调试 SSL 连接,请使用 openssl 并尝试以下操作:
openssl s_client -connect jboss.server.com:443
openssl s_client -connect jboss.server.com:443
or is it is an SSLV3 server
或者它是 SSLV3 服务器
openssl s_client -connect jboss.server.com:443 -ssl3
openssl s_client -connect jboss.server.com:443 -ssl3
This should print a lot of interesting information.
这应该会打印出很多有趣的信息。
回答by Michael Munsey
I think this is related to a Java 7 bug. It is hard to be sure without more details.
我认为这与Java 7 错误有关。没有更多细节就很难确定。
回答by DMHarris
Was this ever resolved?
这曾经解决过吗?
I had the exact same problem, essentially I was receiving a handshake exception immediately following the clientHello. So The chain of events was
我遇到了完全相同的问题,基本上我在 clientHello 之后立即收到握手异常。所以事件链是
- I would present my certificate to the server
- Server would imediately respond with a handshake failure. (I would not even get a Server Hello back).
- 我会将我的证书提交给服务器
- 服务器会立即响应握手失败。(我什至不会得到 Server Hello 回来)。
Eventually I found that the server was requiring a stronger encryption/decryption algorithm than what I Was supplying in the initial handshake phase (Ie. Client and Server could not agree on a mutual encryption algorithm to use for the ssl communication).
最终我发现服务器需要比我在初始握手阶段提供的更强的加密/解密算法(即客户端和服务器无法就用于 ssl 通信的相互加密算法达成一致)。
I need to install the Unlimited Java JCE (Java Cryptography Extension Policy). There are export rules on using this, so if you ship your code overseas that may have implications..however this is what solved my problem.
我需要安装 Unlimited Java JCE(Java 加密扩展策略)。有使用它的出口规则,所以如果你将你的代码运送到海外可能会产生影响......但是这解决了我的问题。
This link explains how to install the updated policies http://suhothayan.blogspot.com/2012/05/how-to-install-java-cryptography.html
此链接解释了如何安装更新的策略 http://suhothayan.blogspot.com/2012/05/how-to-install-java-cryptography.html
This was also a great link that helped me understand exactly what was going on https://support.f5.com/kb/en-us/solutions/public/15000/200/sol15292.html#id
这也是一个很好的链接,它帮助我准确了解发生了什么 https://support.f5.com/kb/en-us/solutions/public/15000/200/sol15292.html#id
This may or may not be the issue, but when the handshake fails immediately after the client Hello, it looks like the client and the server can not agree on something (in many cases its the encryption algorithms that they will mutually need to communicate).
这可能是也可能不是问题,但是当握手在客户端 Hello 之后立即失败时,看起来客户端和服务器无法就某些事情达成一致(在许多情况下,它们需要相互通信的加密算法)。
回答by Mahmoud Saleh
For me solution was : System.setProperty("https.protocols", "TLSv1.1,TLSv1.2");
对我来说,解决方案是: System.setProperty("https.protocols", "TLSv1.1,TLSv1.2");