事故原由:
业务域名从腾讯云传统型LB切换到应用型LB,客户反馈访问接口异常但没有具体的异常信息,但是我们自己的客户端包括curl、postman测试又都正常!
排查步骤:
让客户端抓包,提供的报文如下:
ssl协议采用的是SSLv2版本,紧接着服务端响应了RST直接结束了。看不出具体是什么原因,这个SSLv2协议见的比较少,所以去找了些资料得知这个协议存在比较大的漏洞(CVE-2016-0703)早就已经被遗弃了,大部分服务端都不支持这个协议了,所以给客户反馈了这个信息,让他们升级客户端版本才能解决,但是由于客户端系统比较老,无法修改,结果只能再把域名切回来。。。
后面找腾讯云的确认传统型LB和应用型LB都是不支持SSLv2协议的,那为什么切回传统型LB就正常了,猜测应该就不是SSL协议的问题了
接着让客户抓了一个正常的包,提供的报文如下:
同样第一个Clent Hello也是SSLv2协议,但是在服务端不支持的情况下会切换到TLSv1,说明客户端也支持TLSv1协议
没办法只能把域名在切到应用型LB上,让他们抓一个详细一点的包:
这下终于看到点有用的信息了,ssl证书错误?不可能我其他客户端都是正常的,看下返回的证书信息
发现匹配到的域名证书和请求的域名不一致,请求到了默认域名的证书了,nginx之前也遇到过同样的问题,猜测是SNI的问题,查看LB配置是开启了SNI的
为了确定是客户端的问题将默认域名改成了请求的域名,结果正常了!!!
结论:
客户端没有携带SNI扩展,CLB这边始终返回默认的证书,导致验证失败,将默认域名修改之后业务恢复正常。后面也了解到客户端用的java版本比较低,导致客户端不知道SNI扩展
SNI的由来和解决的问题:
目前服务器的性能足够支撑我们在一台服务器上通过nginx或apache部署多个站点,暴露多个域名。在http请求中,客户端请求某特定网站时,把请求的域名作为主机头(host)放在 http header 中,从而服务器根据域名可以知道把该请求引向哪个域名服务,并把匹配的网站传送给客户端。但是此方式到 https 就失效了,因为 SSL 在握手的过程中,不会携带host 信息,所以服务端通常返回配置中的第一个可用证书,这就导致不同虚拟主机上的服务不能使用不同证书。
为了解决此问题,产生了 SNI,SNI 中文名为服务器名称指示,是对 SSL/TLS 协议的扩展,允许在单个 IP 地址上承载多个 SSL 证书。SNI 的实现方式是将 HTTP 头插入到 SSL 的握手中,提交请求的 Host 信息,使得服务器能够切换到正确的域并返回相应的正确证书。
SNI兼容性可参照SNI兼容性导致HTTPS访问异常(服务器证书不可信) - Web 应用防火墙 - 阿里云tt
TLS握手过程