Java 如何配置JDK1.6以与仅TLS服务器进行ssl握手
我看到客户端在JDK1.6上运行时握手失败。如何配置JDK1.6以允许客户端连接 我怀疑问题是SSLv2客户机hello或不支持的密码,但无法100%确定是哪种密码 客户端调试输出:Java 如何配置JDK1.6以与仅TLS服务器进行ssl握手,java,ssl,Java,Ssl,我看到客户端在JDK1.6上运行时握手失败。如何配置JDK1.6以允许客户端连接 我怀疑问题是SSLv2客户机hello或不支持的密码,但无法100%确定是哪种密码 客户端调试输出: Allow legacy hello messages: true Is initial handshake: true Is secure renegotiation: false Client, setSoTimeout(61000) called %% No cached client session ***
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
Client, setSoTimeout(61000) called
%% No cached client session
*** ClientHello, TLSv1
Cipher Suites: [SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
***
Client, WRITE: TLSv1 Handshake, length = 75
Client, WRITE: SSLv2 client hello message, length = 101
Client, received EOFException: error
Client, handling exception: javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
Client
, SEND TLSv1 ALERT:
fatal,
description = handshake_failure
我知道另一种方法(不理想)是在远程服务器上允许SSLv2Hello伪协议。我会羞愧地低下头,要求提供商允许SSLv2Hello,但我不确定这是否会允许基于可用密码的连接成功。由于安全问题(CVE-2014-3566或Poodle等),SSLv2和SSLv3是不推荐的协议,因此强制服务器接受它不是一个好主意 也没有必要将客户机的JVM升级到6(只要服务器接受TLSv1),您只需在创建自定义套接字工厂时禁用上述协议(扩展默认的
SSLSocketFactory
),然后在创建套接字时将其删除并设置启用的协议即可
private Socket removeSSLv2v3(Socket socket) {
if (!(socket instanceof SSLSocket)) {
return socket;
}
SSLSocket sslSocket = (SSLSocket) socket;
String[] protocols = sslSocket.getEnabledProtocols();
Set<String> set = new HashSet<String>();
for (String s : protocols) {
if (s.equals("SSLv3") || s.equals("SSLv2Hello")) {
continue;
}
set.add(s);
}
sslSocket.setEnabledProtocols(set.toArray(new String[0]));
return sslSocket;
}
或者,您可以在执行客户机时通过命令行中的属性设置启用的协议(对于Java 6,它只接受TLSv1)
java-Dhttps.protocols=“TLSv1”
或
java-Dhttps.protocols=TLSv1
不幸的是,运行时框架是封闭源代码的,否则我相信我可以使用提供的示例使其工作。我试着在startup命令中设置-Dhttps.protocols系统属性,其中我还设置了-Djavax.net.debug,但SSLv2Hello仍然存在,然后您可以将Java版本更新到6以运行客户端,Java 7默认使用TLSv1,Java 8使用TLSv1.2我不确定“将Java版本更新到6以运行客户端”是什么意思-我已经在运行1.6了。我使用JDK1.7成功地进行了测试,它选择了TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA-这个密码在Java 6中受支持吗-如果他们启用SSLv2Hello,它会在1.6客户端工作吗?抱歉,语言错误,我的意思是“最多6”大于6。Java 6支持TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,如果服务器端接受SSLv2Hello,它将起作用,但它是一个不推荐使用的(且不安全的)协议,所以保留Java 7是最好的选择。服务器现在启用了SSLv2Hello,我可以从ssllabs报告中看到SSL 2握手兼容性:是-但是握手仍然会因EOFEException而失败。ssllabs报告显示:Java6U45脚注:无SNI2服务器闭合连接,其中脚注2为:不支持虚拟SSL主机(SNI)。如果服务器使用SNI,则连接到默认站点。有什么想法吗?假设存在$JAVA\u HOME/lib/security/JAVA.security
文件中的jdk.tls.disabledAlgorithms
的值是多少?您可以在那里禁用SSLv2Hello和SSLv3。如果您共享同一虚拟机,您可能会中断另一个正在运行的应用程序,更改java.security默认值不是一个好主意。@vzamanillo修改配置文件(该文件存在以进行修改,以便在需要时更改配置)更可靠,与在源代码不可用的遗留应用程序中强制安装自定义代码相比,速度更快,所需的人力更少,成本更低。“更多代码”并不是每个问题的解决方案-事实上,“更多代码”通常是最不可靠和最昂贵的选项。我并不完全同意,但这是另一个讨论。作为记录,在java.security中添加jdk.tls.disabledAlgorithms=SSLv2Hello并没有阻止发送SSLv2客户端hello消息。
SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
sslContextBuilder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContextBuilder.build(), new String[] { "TLSv1" }, null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
java -Dhttps.protocols="TLSv1" <MyClient>
java -Dhttps.protocols=TLSv1 <MyClient>