连接到 https 站点时发生 SSLHandshakeException
SSLHandshakeException while connecting to a https site
我正在尝试通过 jmeter(版本 2.13,java 版本 - 1.8u31)记录 https site,并且在连接到 https 站点时出现 SSLHandshakeException。错误信息是
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2011)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1113)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1363)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1391)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1375)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:436)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:294)
at org.apache.jmeter.protocol.http.sampler.MeasuringConnectionManager$MeasuredConnection.open(MeasuringConnectionManager.java:107)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:643)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
at org.apache.jmeter.protocol.http.sampler.HTTPHC4Impl.executeRequest(HTTPHC4Impl.java:517)
at org.apache.jmeter.protocol.http.sampler.HTTPHC4Impl.sample(HTTPHC4Impl.java:331)
at org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy.sample(HTTPSamplerProxy.java:74)
at org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase.sample(HTTPSamplerBase.java:1146)
at org.apache.jmeter.protocol.http.proxy.Proxy.run(Proxy.java:240)
我已经打开了 SSL 的调试日志记录,但我无法理解根本原因。好像是java客户端发送了ClientHello但是没有收到ServerHello消息(where服务器选择了客户端和服务器都支持的最高版本的SSL和最好的密码套件发送这个信息给客户)。我看到客户端发送、读取和接收的协议版本之间存在差异(TLSv1.1 与 TLSv1.2)
这是根本原因吗?如果是这样,我该如何解决?
日志粘贴在这里 - Java SSLHandshakeException Logs - Pastebin.com
更新
正如@Anand Bhatt 所建议的,我用 ssllabs 分析了网站并理解了以下内容
- 服务器不支持 java 8
支持的 TLSv1.2
- 服务器仅支持一种密码套件 - TLS_RSA_WITH_AES_256_CBC_SHA
- Java 8u31 不支持服务器支持的密码套件,这很可能是问题所在。
听起来对吗?如果是这样,我们如何让 java 8 客户端支持服务器支持的密码套件?
SSLlabs 显然正在测试 "out of the box" 支持。 Java 加密有一个可以追溯到 1990 年代的罐子,当时美国政府严格限制加密软件的出口,
因此,当时的 Sun 现在发布的 JRE(或 JDK)Oracle 不允许使用 256 位 对称加密,这是您的服务器要求的。您必须下载并安装
您的Java(主要)版本的“JCE Unlimited Strength 管辖政策文件”; 8 在 http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html 。
文件中的 README 提供了冗长的细节,但基本上你替换了 JRE/lib/security.
中的两个小 jar 文件
TLSv1.2 现在 不是真正的问题。 TLS 协议自动协商两端支持(和启用)的最高版本。
Java 8 实施 SSLv3、TLSv1.0、TLSv1.1 和 TLSv1.2,但最近更新(8u31 或 7u75 及更高版本)禁用 SSLv3 默认 因为 POODLE;
如果您愿意,可以重新启用它,但您应该不愿意这样做。 (Java 7 实现了相同的协议版本,但 client 默认禁用 1.1 和 1.2,因为几年前发布时存在兼容性问题。)
但是,由于 POODLE 和 BEAST,一些安全机构不再接受 SSLv3 和 TLSv1.0
足够安全;一个重要的例子是信用卡和借记卡,详见 https://security.stackexchange.com/a/87077/39571。
TLSv1.2 在 1.1 的基础上进行了一些技术改进,使其成为今天的 首选 ,并且未来可能会发现这些
改进至关重要;如果您的服务器不支持 1.2(可能更高)在那个时候,您就会有麻烦了。同样,服务器唯一的事实
支持的套件使用纯 RSA 密钥交换,即非前向保密,现在被认为是次优的,并且随着时间的推移可能变得不可接受。
keytool(至少对于通常使用的密钥库和信任库文件)与对称密码学无关。
如果服务器使用 CA root(或更准确和更一般的信任锚),则可能相关
您的 JRE and/or 应用程序不信任,and/or 如果服务器需要 客户端身份验证 在 SSL/TLS 级别 ,
这是相当罕见的。 (大多数网站在 Web 应用程序级别或至少 HTTP 级别(如果有的话)进行身份验证。)
SSLLabs 对服务器证书链(以及其他一些东西)的检查通常比 Java 的更严格,并且它们
没有在那个区域抱怨,所以你在那里不太可能有问题。
我正在尝试通过 jmeter(版本 2.13,java 版本 - 1.8u31)记录 https site,并且在连接到 https 站点时出现 SSLHandshakeException。错误信息是
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2011)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1113)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1363)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1391)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1375)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:436)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:294)
at org.apache.jmeter.protocol.http.sampler.MeasuringConnectionManager$MeasuredConnection.open(MeasuringConnectionManager.java:107)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:643)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
at org.apache.jmeter.protocol.http.sampler.HTTPHC4Impl.executeRequest(HTTPHC4Impl.java:517)
at org.apache.jmeter.protocol.http.sampler.HTTPHC4Impl.sample(HTTPHC4Impl.java:331)
at org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy.sample(HTTPSamplerProxy.java:74)
at org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase.sample(HTTPSamplerBase.java:1146)
at org.apache.jmeter.protocol.http.proxy.Proxy.run(Proxy.java:240)
我已经打开了 SSL 的调试日志记录,但我无法理解根本原因。好像是java客户端发送了ClientHello但是没有收到ServerHello消息(where服务器选择了客户端和服务器都支持的最高版本的SSL和最好的密码套件发送这个信息给客户)。我看到客户端发送、读取和接收的协议版本之间存在差异(TLSv1.1 与 TLSv1.2)
这是根本原因吗?如果是这样,我该如何解决?
日志粘贴在这里 - Java SSLHandshakeException Logs - Pastebin.com
更新
正如@Anand Bhatt 所建议的,我用 ssllabs 分析了网站并理解了以下内容
- 服务器不支持 java 8 支持的 TLSv1.2
- 服务器仅支持一种密码套件 - TLS_RSA_WITH_AES_256_CBC_SHA
- Java 8u31 不支持服务器支持的密码套件,这很可能是问题所在。
听起来对吗?如果是这样,我们如何让 java 8 客户端支持服务器支持的密码套件?
SSLlabs 显然正在测试 "out of the box" 支持。 Java 加密有一个可以追溯到 1990 年代的罐子,当时美国政府严格限制加密软件的出口, 因此,当时的 Sun 现在发布的 JRE(或 JDK)Oracle 不允许使用 256 位 对称加密,这是您的服务器要求的。您必须下载并安装 您的Java(主要)版本的“JCE Unlimited Strength 管辖政策文件”; 8 在 http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html 。 文件中的 README 提供了冗长的细节,但基本上你替换了 JRE/lib/security.
中的两个小 jar 文件TLSv1.2 现在 不是真正的问题。 TLS 协议自动协商两端支持(和启用)的最高版本。 Java 8 实施 SSLv3、TLSv1.0、TLSv1.1 和 TLSv1.2,但最近更新(8u31 或 7u75 及更高版本)禁用 SSLv3 默认 因为 POODLE; 如果您愿意,可以重新启用它,但您应该不愿意这样做。 (Java 7 实现了相同的协议版本,但 client 默认禁用 1.1 和 1.2,因为几年前发布时存在兼容性问题。)
但是,由于 POODLE 和 BEAST,一些安全机构不再接受 SSLv3 和 TLSv1.0 足够安全;一个重要的例子是信用卡和借记卡,详见 https://security.stackexchange.com/a/87077/39571。 TLSv1.2 在 1.1 的基础上进行了一些技术改进,使其成为今天的 首选 ,并且未来可能会发现这些 改进至关重要;如果您的服务器不支持 1.2(可能更高)在那个时候,您就会有麻烦了。同样,服务器唯一的事实 支持的套件使用纯 RSA 密钥交换,即非前向保密,现在被认为是次优的,并且随着时间的推移可能变得不可接受。
keytool(至少对于通常使用的密钥库和信任库文件)与对称密码学无关。 如果服务器使用 CA root(或更准确和更一般的信任锚),则可能相关 您的 JRE and/or 应用程序不信任,and/or 如果服务器需要 客户端身份验证 在 SSL/TLS 级别 , 这是相当罕见的。 (大多数网站在 Web 应用程序级别或至少 HTTP 级别(如果有的话)进行身份验证。) SSLLabs 对服务器证书链(以及其他一些东西)的检查通常比 Java 的更严格,并且它们 没有在那个区域抱怨,所以你在那里不太可能有问题。