HttpsURLConnection 的禁用证书验证仍然出现 javax.net.ssl.SSLHandshakeException:收到致命警报:handshake_failure

Posted

技术标签:

【中文标题】HttpsURLConnection 的禁用证书验证仍然出现 javax.net.ssl.SSLHandshakeException:收到致命警报:handshake_failure【英文标题】:Disabled certificate validation for HttpsURLConnection still getting javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure 【发布时间】:2015-11-14 08:19:03 【问题描述】:

我正在编写一些将 HTTP GET/POST 请求发送到目标服务器的代码。当应用程序尝试建立与安全服务器 (https) 的连接时,就会出现问题。为此,我使用了 HttpsURLConnection,如下所示:

url = new URL("https://www.sendspace.com/");
String input, htmlResponse = "";
HttpsURLConnection con;

con = (HttpsURLConnection)url.openConnection();
BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));

while ((input = br.readLine()) != null)
    htmlResponse += input;

br.close();

但是,它显示了以下错误:

javax.net.ssl.SSLHandshakeException:收到致命警报: 握手失败

因此,我把上面的代码改成这样:

url = new URL("https://www.sendspace.com/");
String input, htmlResponse = "";

SSLUtilities.trustAllHostnames();
SSLUtilities.trustAllHttpsCertificates();
HttpsURLConnection con;
// code below has not been changed

它使用了SSLUtilities.java。 但是,我注意到这样做没有任何效果,因为我仍然再次收到完全相同的错误:

javax.net.ssl.SSLHandshakeException:收到致命警报: 握手失败

同样,我也尝试使用不同的方法,包括在启动 HttpsURLConnection 之前使用此行来使用 SSLCertificateValidation.java:

SSLCertificateValidation.disable();

甚至使用它返回与前面解释的完全相同的错误。我想确切地知道为什么这种方法不起作用,我怎么可能绕过这个错误?

请注意以下几点:

    不用说,我已经对这个问题进行了广泛的搜索,并且已经花费了大量时间,尝试了不同的建议和代码示例,但无济于事。我知道这个错误已经在很多问题中出现,但我没有找到与我自己相关的已经存在的具体答案。

    我知道并理解由于禁用证书验证而出现的安全问题。但是,由于此应用程序将连接到 100 到 200 个不同的服务器(根据需要),因此在每个服务器的基础上管理证书是不可行的。因此,除非有人可以说明(a)检索、(b)存储和(c)在每个服务器的基础上(在运行时)使用正确证书的方法,所有这些都必须以编程方式完成,无需任何手动工作,建议“干净”的方式来做这件事并不是解决这种情况的方法。

谢谢。

【问题讨论】:

我试图调查我试图连接的服务器的证书,在上面的例子中(sendspace.com),因此我发现了这个:ssllabs.com/ssltest/analyze.html?d=sendspace.com,它清楚地说明了一个问题在所有带有握手的 Java 版本中。但这仍然不能解释为什么验证禁用尝试不起作用。 您引用的代码似乎至少有 11 年的历史并且质量可疑。自 1.4 以来,com.sun.ssl.* 类未与 SSL 一起使用。 @EJP:我相信你指的是SSLUtilities.java中的代码,我使用的第二种方法呢?它不应该工作吗?此外,您能否指导我采用一种适合我的目的的方法?谢谢。 【参考方案1】:

握手失败不是证书验证错误,因此您无法通过忽略证书错误来修复它(无论如何这都是个坏主意)。 SSLLabs 页面更清楚地说明了问题的真正原因:

Java 8u31   Protocol or cipher suite mismatch   

如果您查看服务器支持的密码(同样在 SSLLabs 报告中),您可以看到所有密码都包含密钥大小为 256 的 AES。但在 documentation about supported key sizes 中指出,由于出口限制AES 支持的最大密钥大小为 128。这意味着您的客户端仅提供 AES128 密码,而服务器仅接受 AES256 密码,即没有共享密码。

要解决此问题,您必须按照参考文档中的说明进行操作:

如果需要更强的算法(例如 256 位密钥的 AES),则必须获取 JCE Unlimited Strength Jurisdiction Policy Files 并将其安装在 JDK/JRE 中。

【讨论】:

谢谢。尽管我事先知道 SSLLabs 页面,但我并没有想到密钥长度的差异。但是,我想在上面的答案中添加一些更多的解决方案,供那些不希望通过手动将 JCE 文件添加到 JDK/JRE 的人使用。如需完整说明,请查看此答案:***.com/a/22492582/4905539 谢谢。我将平台从 1.7 更改为 1.8,现在一切正常。

以上是关于HttpsURLConnection 的禁用证书验证仍然出现 javax.net.ssl.SSLHandshakeException:收到致命警报:handshake_failure的主要内容,如果未能解决你的问题,请参考以下文章

java HttpsURLConnection怎么绕过证书,原理是啥

关于JAVA发送Https请求(HttpsURLConnection和HttpURLConnection)

在 HttpsURLConnection 中禁用 SSL 作为协议

使用客户端证书和 Android 的 HttpsURLConnection 通过 SSL 上传文件

java HttpsURLConnection怎么绕过证书,原理是啥

java HttpsURLConnection怎么绕过证书,原理是啥