为啥 Java 的 SSLSocket 会发送版本 2 的客户端 hello?

Posted

技术标签:

【中文标题】为啥 Java 的 SSLSocket 会发送版本 2 的客户端 hello?【英文标题】:Why does Java's SSLSocket send a version 2 client hello?为什么 Java 的 SSLSocket 会发送版本 2 的客户端 hello? 【发布时间】:2011-06-08 15:38:09 【问题描述】:

SSLSocket.getEnabledProtocols() 方法返回以下内容:[SSLv2Hello, SSLv3, TLSv1]。事实上,当我调用 connect() 并打开 SSL 调试时,我看到使用了 v2 客户端 hello:

main, WRITE: TLSv1 Handshake, length = 81
main, WRITE: SSLv2 client hello message, length = 110

但我发现了两个(诚然是旧的)参考资料说 JSSE 确实支持 SSL 版本 2:

来自Fundamental Networking in Java:

'SSLv2Hello' 是一个伪协议,它允许 Java 使用 SSLv2 'hello message' 发起握手。这不会导致使用 Java 根本不支持的 SSLv2 协议。

来自JSSE Reference Guide:

J2SDK 1.4 及更高版本中的 JSSE 实现实现了 SSL 3.0 和 TLS 1.0。它没有实现 SSL 2.0。

现在,我的理解是仅当客户端确实支持 SSL 2.0 版时,才应发送 2.0 版客户端问候。来自RFC 2246:

支持 SSL 2.0 版服务器的 TLS 1.0 客户端必须发送 SSL 2.0 版客户端问候消息 [SSL2] ... 警告: 发送 2.0 版客户端问候消息的功能将被逐步淘汰。

那么为什么 Java 使用它呢?

【问题讨论】:

在 Sun/Oracle Java 6 的 JSSE 上默认开启 SSLv2Hello,但在 Java 7 或更高版本上不开启。例如,它会中断与 www.howismyssl.com 的 Java 6 连接。 【参考方案1】:

Sun 的 JSSE 不支持 SSLv2,但它支持SSlv2ClientHello,以支持一些需要它的 SSL 服务器。您可以通过将其从启用的协议中删除来将其关闭。

IBM 的 JSSE 确实完全支持 SSLv2。

来自JSSE Reference Guide:

例如,一些较旧的服务器 实现只讲 SSLv3 和 不懂 TLS。理想情况下,这些 实施应协商 SSLv3,不过有的干脆挂断。为了 向后兼容性,某些服务器 实现(例如 SunJSSE)发送 SSLv3/TLS ClientHellos 封装在 SSLv2 ClientHello 数据包。一些 服务器不接受这种格式,在 这些情况使用 setEnabledProtocols 来 禁用封装的发送 SSLv2 ClientHellos。

我想“服务器实现”应该是上面的“SSL 实现”。

编辑:感谢您引用我的书!

【讨论】:

感谢您的回答。您是说这些服务器在收到 V2 客户端问候后会使用 v3 响应? 另外,出于好奇,您知道指南指的是哪些服务器吗? ;-) @Matt Solnit:(a)是(b)不是。 请注意,这个答案在 Java 7 中已经过时,但问题也是如此。 Java 在 Java 7 中停止这样做。【参考方案2】:

我遇到了同样的问题,我们的 RCP 应用程序出现了这个错误,它试图访问我们只处理 TLS 协议的 nginx。但是我们使用的 openjdk 有一个 TLS 错误,在某些情况下会以:javax.net.ssl.SSLException: Received fatal alert: bad_record_mac 结尾。所以我试图找到一种方法来使用不同的协议来进行握手,比如 SSLv3。起初我认为SSLv2Hello 是握手协议!但事实并非如此!

SSLv2 从未在 sun jdk 或 openjdk 中实现,这个SSLv2Hello 不是握手的实际协议,它是为了向后兼容(我的猜测是因为某些服务器存在的可能性),它将被使用用于协商将用于实际握手的可用协议!

在这个link上搜索Stoinov的答案,他把答案包裹得很好。

【讨论】:

以上是关于为啥 Java 的 SSLSocket 会发送版本 2 的客户端 hello?的主要内容,如果未能解决你的问题,请参考以下文章

Android 6 及更高版本中的 Android SSLSocket 握手失败

[Unsupported ciphersuite][Java SSLSocket]

java SSLContext

Java SSLSocket 和 HTML5 之间的通信

使用 SSLSocket 的 SOCKS5 代理

SSLSocket 通过另一个 SSLSocket