SSLv2Hello 协议引发的连接拒绝

有开发人员问我, 有没有见过这个 Java 应用报出的异常消息: IO Error: Remote host terminated the handshake. 从这个message看, 这个是说无法通过握手建立连接, 单纯从这个消息看, 看不出来什么原因.

背景

这个应用最近更改了不少文件, 然后重新发布新版本, 就出现了这个错误. 出这个错误的上下文是: 这是一个连接 Oracle 数据的连接, 使用的是TSLv1.2加密连接.

他们问了DBA, DBA 说数据库完好, 问了网络, 网络也没有其它问题.

诊断

最简单的方法是抓包, 查看具体的握手失败的原因. 抓包后看到如下的 SSL client hello 协议内容, 然后服务器就拒绝了:
client_hello.png

从上面的截图我们可以看到, tcp 三次握手, 正常. 然后客户端发送 client hello, 服务器直接就发了 FIN, 要拒绝连接.

在看 client hello 的具体消息, 从消息可以看到, 这里上面写的是 SSLv2, 难道这是1995年使用的 SSL 2.0? 看上去很奇怪.

如果比较熟悉 TLS 协议, 我们可以知道, 在TLS 层, 又分为 TLS record 协议, 它内部又封装了具体的 TLS 子协议, 分别是: Application, Alert, Handshake, ChangeCipherSpec. 而 record 协议的第一个字节表示子协议的类型.

然而我们这个截图里面, 前两个字节是 80 b3, 表示内容长度, 关键是 Wireshark 认识这种格式. 太诡异了.

然后仔细查看 Wireshark 的解析, 我们看到 Wireshark 标注的是: SSLv2 Record Layer: Client Hello.

关于 SSLv2Hello

顺着这个关键字, 我们终于找到了另外一种协议: SSLv2Hello. 这是一种伪协议, 它是 Oracle 之前发明的, 并且现在已经不在使用的. 它的主要作用是在客户端发送一个SSLv2Hello消息, 试探一下服务端使用的到底是哪种协议, 是 TLS 1.1, 还是 TLS 1.2.

JDK 里面在 JDK 7 之前默认是有这种协议的, 之后 Oracle disable 了它.

-- 未完待续 --

标签: none

添加新评论