我有一个使用SSL / TLS连接到Web服务器的Java程序,并通过该连接发送各种HTTP请求。服务器是localhost并使用自签名证书,但我的代码使用自定义TrustManagers,并忽略无效证书。它一直运作到现在。
服务器上的唯一区别是它曾用于运行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
答案 0 :(得分:25)
所以我发现了问题。 Java中可能存在错误,但客户端似乎启动了TLSv1握手,但随后发送了SSLv2客户端问候消息,此时服务器拒绝连接。
即使您使用TLS实例创建SSLContext,也会发生这种情况:
SSLContext sslContext = SSLContext.getInstance("TLS");
解决方案是在进行任何连接尝试之前设置系统属性:
System.setProperty("https.protocols", "TLSv1");
可能有其他解决方案,但这个对我有用。
答案 1 :(得分:4)
您提供的信息与您的堆栈跟踪信息非常少 我在这里猜一猜 我怀疑在新服务器中,协议是TLSv1,而您的客户端尝试连接SSLv3(或更少),因此握手失败。
将您的客户更改为使用更高版本的TLS
或
使您的网络服务器也支持SSLv3。我知道如何在Tomcat中执行此操作,而不是在JBoss中执行此操作。
如果这不起作用,请使用更多信息更新帖子(以及完整的堆栈跟踪)
您应该启用ssl调试信息-Djavax.net.debug=ssl
答案 2 :(得分:4)
这是否曾经解决过?
我遇到了完全相同的问题,基本上我在clientHello之后立即收到握手异常。所以事件链是
最终我发现服务器需要比我在初始握手阶段提供的更强的加密/解密算法(即客户端和服务器无法就用于ssl通信的相互加密算法达成一致)。 / p>
我需要安装Unlimited Java JCE(Java加密扩展策略)。有关使用此功能的出口规则,因此如果您将代码发送到海外可能会产生影响..这就是解决我问题的方法。
此链接说明如何安装更新的策略 http://suhothayan.blogspot.com/2012/05/how-to-install-java-cryptography.html
这也是一个很好的链接,帮助我准确理解发生了什么 https://support.f5.com/kb/en-us/solutions/public/15000/200/sol15292.html#id
这可能是也可能不是问题,但是当客户端Hello之后握手立即失败时,看起来客户端和服务器无法就某些内容达成一致(在很多情况下,它们是相互需要的加密算法)通信)。
答案 3 :(得分:0)
您很可能看到此错误,因为您的JBoss 7实例无法访问您的JBoss 6可访问的密钥库。
我建议的是以下内容。
您的自签名服务器证书必须导入信任库
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
答案 4 :(得分:0)
堆栈跟踪来自您的客户端代码和您的客户端'Received [a]致命警报'。换句话说,SSL错误发生在Jboss中,而不是您的客户端。
因此,您的客户端自定义TrustManagers与它无关。我的猜测是,您的新Jboss 7配置为需要客户端证书,而您的客户端不提供任何证书。
要调试SSL连接,请使用openssl并尝试以下操作:
openssl s_client -connect jboss.server.com:443
或者它是SSLV3服务器
openssl s_client -connect jboss.server.com:443 -ssl3
这应该会打印很多有趣的信息。
答案 5 :(得分:0)
我认为这与Java 7 bug有关。没有更多细节,很难确定。
答案 6 :(得分:0)
对我而言,解决方案是:System.setProperty("https.protocols", "TLSv1.1,TLSv1.2");