为啥 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 握手失败