最近碰到了一些用户反馈生产问题
报错 wss 在浏览器chrome 100里面连接错误。
。
还有ipad 15.1上 safari报错
。
代码没有动过,已经无法从应用层来查找到问题。所以尝试从wireshark抓包来分析下发生了什么。
抓了一下他们的包 都是一致的。tls握手过程中突然服务端发送了一个fin关闭了连接,握手中断。
在chrome100以下没这个问题。用户反馈,安装了chrome100的用户都出现了 这个问题。高度怀疑是 chrome导致的问题。
所以去看了下chrome100的更新日志。
chrome 更新日志
基本可以确定是 这个更新导致的问题。 即在wss握手过程中tls 添加了alpn拓展。
先来回顾下tls握手过程。 tls握手之前会先进行tcp三次握手。 tls主要是先非对称加密交换计算对称秘钥的参数,再分别在服务器和客户端分别根据这些参数计算出对称加密秘钥,还包括 tls版本协商,和加密套件(tls.handshake.ciphersuites) 签名算法的协商。以及证书的校验。 拓展功能,包括(serve_name等)是通过 extension来实现的。
在tls握手的最后阶段需要切换到 应用层,以前是通过 npn 来完成协商的,后来出现了 alpn这种方式,用来协商客户端和服务器端到底应该使用什么应用层协议进行沟通。
上面的alpn,全称是Application Layer Protocol Negotiation,应用层协议协商。 即协商使用http 1.1 还是http2.
alpn是什么
前面已经讲了,在tls握手的最后阶段需要切换到 应用层,就有 npn 和 alpn两种方式来协商。 alpn是基于npn来改进的。
npn, 它是客户端在client hello 里面携带一个npn flag, 服务端收到后知道客户端支持npn,所以 server hello里面携带一个npn flag+protocol list 告诉客户端支持什么协议, 第三次握手客户端再从协议列表里面选择一种应用层协议告诉服务器。
所以npn总共需要进行三次握手才能协商好使用哪一种应用层协议。
alpn: 则是在 client hello里面 告诉服务端支持哪些协议, 服务端在server hello 里面选择协议。
alpn和 npn区别: alpn直接从客户端alpn里面选择出协议,少了一步交互过程。
抓包重现
安装了一个chrome100,发起一次wss请求,用wireshark 抓了一下包。
Extension: application_layer_protocol_negotiation (len=11)
Type: application_layer_protocol_negotiation (16)
Length: 11
ALPN Extension Length: 9
ALPN Protocol
ALPN string length: 8
ALPN Next Protocol: http/1.1
此时服务端也应该在server hello里面使用extension.alpn来说明自己选择的应用层协议 如下:
Extension: application_layer_protocol_negotiation (len=11)
Type: application_layer_protocol_negotiation (16)
Length: 11
ALPN Extension Length: 9
ALPN Protocol
ALPN string length: 8
ALPN Next Protocol: http/1.1
如果此时服务端没有做升级,就无法理解该alpn拓展导致握手失败。
实际抓包发现:服务端的server hello里面没有返回alpn。
服务端因为还是使用的npn,没有读到 npn拓展flag,握手失败,返回 fin关闭连接
总体来看一下
先进行了三次tcp握手, client hello, 服务端发送 server hello, 并且服务端立即发送了fin 包。随后tcp连接关闭。即出现了刚开始的截图的那个wss连接问题。
解决方案
对于ipad 15.1 ,可以通过关闭ipad里面safari的advanced -> exprimental features 里面的nsursession websocket
对于chrome 100 ,没有相关的开关可以关闭,只能服务端做tls升级支持 alpn和npn两种应用协商方式。
client hello里面 客户端发送了一个 alpn包提供给服务器选择 复习知识。
主要是下面几步:
即验证身份-> 安全套件共识 -> 传递秘钥 ->对称加密通信。
上面所说的
tls npn:
- 客户端发起 client hello消息,包含npn flags ,
- 服务端收到之后, 返回npn flags+支持的协议列表(http1.1 http2),证书等。
- 客户端再来选择 协议名称
http2 改进 alpn(应用层协议协商)
客户端告诉支持哪些协议,服务端做选择,
Q&A:
客户端可以同时添加两种拓展?
可以的,可以兼容npn的情况下支持alpn ,可以同时在client hello 里面添加 npn可alpn拓展, 服务端自己来选择支持哪一种
服务端如果支持alpn,则直接返回选中的alpn即可。
alpn和 upgrade header区别
- 工作层级不同,alpn工作在tls层, upgrade在应用层
- alpn在启用tls时候使用, upgrade 在明文状态下使用
- alpn支持客户端主动发起协商, upgrade 支持服务端强制指定协议兼容性更好。