https 握手失败问题排查全记录
起
“我都测过了,不可能有问题!!!”老张大喊道。然而,一到上线就啪啪打脸。这个职业就是这么刺激!
事情是这样的,系统中有一个功能是发起 http 请求,请求地址是可配置的,系统已经在测试环境跑了有段时间了,无论是http,还是 https 请求,那都是经历过历史考验的。然而,上线后,测试同学配置了个 https 请求进行回归测试的时候,神奇的事情发生了,报错 503,错误信息是 handshake failed
。这可吓坏了老张,毕竟都是要面儿的人。
经验丰富的老张凭借莫名的自信,迅速做出了判断,这肯定是配置的 url 服务问题,不信我 curl 一下给你看。啪啪啪啪,一顿急促而不慌张的操作:
curl https://xxxxx.com/xxxx
然而,控制台显示了正常的返回信息。
老张不禁倒吸一口凉气,这是要翻车了。遇事不能急,老张迅速自己配置了一个 https 地址,经过系统调用,是正常的。现在情况很不乐观:
老张自己在环境中配置了一条 https 地址,是可以正常调用的
测试同学在环境中配置了一条 https 地址,调用失败
测试同学用的地址,使用 curl 命令是可以正常调用的
打开搜索引擎,输入: https handshake failed,然后一排排结果显示在了屏幕上。老张发扬蚂蚁啃骨头的精神,试图从一条条冷冰冰的文字中找到一些线索。然而,这触及到了老张的知识盲区,并没有找到确切的答案。但也并不是没有用,搜索出的各种信息在老张脑子里不断的闪现,就等某一瞬间擦出知识的火花。
这次搜索成果如下:
证书问题(感觉不会有问题,毕竟老张自己配置的https地址是可以正常访问的)
加密算法问题(这..., 不太确定, 老张对这方面知识也是半知半解)
SNI 问题(这是个啥?这在老张的知识盲区内)
...
为什么只列上面的这些成果,因为老张的知识储备只能支撑他对这些结果有些印象。
时间一点点流逝,火花并没有迸发,脑子却熬成了一锅粥。
俗话说的好:网络不通,还得抓包。老张祭出了神器——tcpdump。先抓了一个请求失败的包:
前三条是 tcp 三次握手,说明网络是通了,然后客户端发起了 Client Hello 包,这是 https 握手的第一步,下一行是服务端正常的 ack 响应。奇怪的是最后一行,服务端发送了 RST 包,终止连接,这也就是请求报 handshake failed 的原因了。于是缩小问题排查范围,再次打开搜索引擎,输入:https handshake failed rst ack,新的结果显示在页面上,又是枯燥的找线索环节。这次搜索到的结果也差不多。
老张心想,那就把搜索到的线索一个个进行排查吧。
首先,证书问题,应该不太可能,因为有的 https 地址可以调通,有的不可以。排除掉该原因,当然也可能是误判。
第二条,服务端不支持客户端的加密算法,感觉很像这个原因,因为存在如下情况:请求失败的 url 指向的服务器不支持客户端的加密算法,请求成功的 url 指向的服务器支持客户端的加密算法,这能说得通。
怎么排查呢?先看一下客户端发送 Client Hello 所支持的算法:
这,怎么下手?还是先看下通过 curl 调用该接口成功时使用了什么算法吧。
不愧是调用成功了,这数据包看着都舒服。https 加密算法是服务端来确定的,在 Server Hello 包中发送给了客户端,那就看看这个包的内容。
然鹅,这个加密算法客户端发送的 Client Hello 包是包含的。老张再次经历了 debug 滑铁卢。这可咋办,那只能看看第三原因了,也就是 SNI。可这完全不懂啊。
所谓书到用时方恨少,不会的早晚要补上。只能先简单看下 SNI 是个什么东西了。于是又是一波搜索引擎走起。关于 SNI 就不做太多介绍了,大家可以自己搜一下。简单来说,就是一台服务器配置了多个服务,即有多个域名,当然相应的配置了多个证书,他们监听了相同的端口,这样客户端发送 Client Hello 后,服务端不知道该用哪个证书进行回应,因此服务端就选择困难症犯了,干脆撂挑子不玩了。而 SNI 就是解决这个问题的,SNI 是 TLS 的一个扩展,客户端发送 Client Hello 包时会携带一个域名,这样服务端接收到请求后就可以根据这个域名去找相应的证书了。
那就看看是不是这个原因,先看看成功的请求有没有带这个东西。打开 Client Hello 包的详情,还真找到了。
图中打码的地方就是域名了。再看看请求失败的包,有没有该扩展:
没有!!!这个把老张高兴坏了,胜利就在眼前了,赶紧试一试是不是这个原因。老张用的 lua-resty-request 这个库,搜一下,只要加个 server_name 参数就可以了。赶紧改了一下,发布,测试!成了!!!
总结
高兴之余,老张也陷入了沉思,为啥会出现这种失误,明明一个参数就能解决的事儿,却费了这老半天的劲!
总结下来:
对协议了解的还是不够全面,自己用到的东西还是要系统的学习一下的;
对使用的库不够了解,如果能弄清楚库方法的各个参数的用途,也许也就避免这个问题了。
排查问题是枯燥,需要不断的搜索,尝试,尤其是在自己不熟悉的领域,更是需要大量的尝试。但问题解决后带来的快乐告诉老张,这些都是值得的。
不过,还是得多读书,懂的越多,会的工具越多,排查起问题来才能有更多思路,共勉。
老张排查问题三板斧:
推锅。当然并不是真的推锅,主要是确认问题所在位置,是自己的代码有问题,还是其他关联系统有问题。
搜索引擎走一波。如果能找到答案就不用加班了。
抓包。网络问题的终极神器,这就不用多说了。
版权声明: 本文为 InfoQ 作者【lockdown56】的原创文章。
原文链接:【http://xie.infoq.cn/article/2a5575facd4318682433e50ef】。文章转载请联系作者。
评论