Java 接收SSLHandshakeException:尽管我的客户端忽略了所有证书,但握手失败
我有一个Java程序,它使用SSL/TLS连接到Web服务器,并通过该连接发送各种HTTP请求。服务器是本地主机,使用自签名证书,但我的代码使用自定义信任管理器,并忽略无效证书。到目前为止,它一直运作良好 服务器上唯一的区别是它过去运行jboss 6,现在运行jboss 7。我不确定这是否是配置问题,或者我的代码是否有问题,但如果我尝试使用其他基于Java的程序(如WebScarab或ZAP)进行连接,我会遇到同样的错误 在任何情况下,我能对我的代码做些什么来解决这个问题吗?以下是完整的错误:Java 接收SSLHandshakeException:尽管我的客户端忽略了所有证书,但握手失败,java,ssl,jboss7.x,Java,Ssl,Jboss7.x,我有一个Java程序,它使用SSL/TLS连接到Web服务器,并通过该连接发送各种HTTP请求。服务器是本地主机,使用自签名证书,但我的代码使用自定义信任管理器,并忽略无效证书。到目前为止,它一直运作良好 服务器上唯一的区别是它过去运行jboss 6,现在运行jboss 7。我不确定这是否是配置问题,或者我的代码是否有问题,但如果我尝试使用其他基于Java的程序(如WebScarab或ZAP)进行连接,我会遇到同样的错误 在任何情况下,我能对我的代码做些什么来解决这个问题吗?以下是完整的错误:
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)
以下是失败前的调试消息:
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
您看到这个错误很可能是因为JBoss 6可以访问的密钥库不能被JBoss 7实例访问 我的建议如下 必须将自签名服务器证书导入信任库
keytool -import -alias gridserver -file server.crt -storepass $YOUR_PASSWORD_HERE -keystore server.keystore
将以下属性添加到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
您提供的信息以及堆栈跟踪非常少。
我在这里猜一猜。
我怀疑的是,在新服务器中,当客户端尝试连接SSLv3(或更少)时,协议是TLSv1,因此握手失败 将您的客户端更改为使用更高版本的TLS 或
使您的Web服务器也支持SSLv3。我知道如何在Tomcat中做到这一点,但不知道如何在JBoss中做到这一点 如果这不起作用,请使用更多信息(以及完整的堆栈跟踪)更新帖子。
您应该启用ssl调试信息
-Djavax.net.debug=ssl
堆栈跟踪来自您的客户端代码,并且您的客户端“收到[a]致命警报”。换句话说,SSL错误发生在Jboss中,而不是您的客户端
因此,客户端自定义信任管理器与此无关。我的猜测是,您的新JBoss7配置为需要客户端证书,而您的客户端没有提供任何证书
要调试SSL连接,请使用openssl并尝试以下操作:
openssl s_客户端-连接jboss.server.com:443
或者它是一个SSLV3服务器
openssl s_客户端-connect jboss.server.com:443-ssl3
这会打印出很多有趣的信息。所以我发现了问题。Java中可能存在错误,但客户端似乎启动了TLSv1握手,但随后发送了SSLv2客户端hello消息,此时服务器拒绝连接 即使使用TLS实例创建SSLContext,也会发生这种情况:
SSLContext sslContext = SSLContext.getInstance("TLS");
解决方案是在进行任何连接尝试之前设置系统属性:
System.setProperty("https.protocols", "TLSv1");
可能还有其他解决方案,但这一个对我有效。我认为这与。没有更多的细节很难确定。这有没有解决过 我遇到了完全相同的问题,基本上我在clientHello之后立即收到了一个握手异常。因此,一连串的事件发生了
这可能是问题所在,也可能不是问题所在,但当握手在客户端打招呼后立即失败时,客户端和服务器似乎无法就某些问题达成一致(在许多情况下,这是他们相互需要通信的加密算法)。对于我来说,解决方案是:
System.setProperty(“https.protocols”,“TLSv1.1,TLSv1.2”);代码>通过Chrome或Firefox等web浏览器,服务器运行正常,因此服务器上的密钥库不是问题所在。认证也不应该成为问题,因为我只是忽略了所有的证书。完整的堆栈跟踪只显示了我的类的连接方法,以及任何调用它的方法。它与以前版本的服务器使用的方法相同。无论如何,这里是调试:对我来说似乎有点奇怪的是,即使我告诉我的程序使用TLS,它似乎想要发送SSLv2客户机hello消息。对我来说,这里也面临类似的问题细节-我们如何识别这个解密错误?我的猜测就是,wild。你的服务器很好。用户384706使您走上了正确的轨道。这更可能是协议版本不匹配。我看到你的服务器是TLSv1/SSLv3,你似乎在发送SSLv2。@布鲁诺:是的,我之前在搜索谷歌时看到过。这是Java中的一个bug吗?当我将SSLContext指定为TLS时,我看不出它怎么可能/应该是默认行为。这不是一个bug,它是经过设计的(SSLv2是用于向后编译的)。请参阅:“例如,getInstance(“SSLv3”)可能会返回一个实现“SSLv3”和“TLSv1”[…]的实例。您可以使用setEnabledProtocols(String[]protocols)方法控制为SSL连接实际启用了哪些协议。”。在您的例子中,https.protocols
负责HttpsURLConnection
的setEnabledProtocols
。对,但这并不能解释为什么当我要求它使用TLS时,它会尝试使用SSLv2客户端hello消息。服务器只支持TLSv1(特别是),从调试消息来看,它看起来像是Java在切换回之前启动了TLSv1握手