A Byte of TLS (Part 1: Overview)
一个前置的问题
很多文献会把 SSL 和 TLS 列在一起,请问他俩是什么关系?
基本流程
下图展示了 TLS 1.2 握手的基本流程:
Cipher Suite Negotiation
-
客户端向服务端发起
Client Hello
,同时发送可以接受的 TLS Version,以及支持的 Cipher Suite。如下图所示: -
服务端收到请求后发起
Server Hello
,同时发送服务端选取的 TLS Version 以及 Cipher Suite。如下图所示:
Authentication
- 在这个阶段,服务端向客户端发送服务端证书,并根据服务端设置向客户端请求客户端证书。收到证书的一基于方验证证书的有效性。
Key Exchange
-
在完成客户端有效性验证后,根据选择的 Cipher Suite,双方进行密钥协商。如果 Cipher Suite 中指定使用 Diffie-Hellman (DHE 或 ECDHE) 算法,服务端会生成一组
ServerKey
发送给客户端。之后服务端会发送Server Hello Done
。如下图所示: -
下图展示了 Server Key 的一些细节。从图中可以看到发送的数据中包含了服务端对 Server Key 的签名以及签名算法和参数。
- 收到 Server Key 之后,客户端会将之与本地生成的 Client Key 组合,并以此生成 Session Key,并将 Client Key 发送给服务端。
- 服务端收到 Client Key 之后会使用同样的方法配合 Server Key 生成 Session Key。
- 正常人看到这一块都会有疑问:两组 Key 都被截获,那岂不是 Session Key 就泄露了?这一块的安全性是由 Cipher Suite 中密钥交换相关的算法(DHE-DSA,DHE-RSA,ECDHE-RSA,ECDHE-ECDSA)保证的。在公共网路上面传输的都是公钥,即便泄露,第三方也无法解算出 Session Key。至于其中的原理,以及如何保证前向安全性,恕鄙人才疏学浅。
And then…
-
客户端在完成发送 Client Key 之后,会向服务端发送 Cipher Spec Message,此消息用于通知服务端启用新生成的 Session Key 进行流加密。之后客户端会发送 Client finished。如下图所示:
-
服务端收到 Cipher Spec Message 后,会启用 Cipher Suite 中约定的流加密算法,之后会向客户端发送 Client finished。从抓包记录来看,最后的握手数据似乎完全是加密的,所以我没有办法展示最后的一组数据的截图。
When I wanna resume a connection
- 客户端使用旧有的 Session ID 发起 Client Hello。
- 服务端检查收到的 Session ID,若可以找到之前的记录,则向客户端发送 Server Hello。
- 服务端与客户端交换 Cipher Spec Message,之后互相发送 Finished。
这一块似乎需要在长连接中才能重现,之前测试使用的都是短连接的 HTTPS,传输的数据也是很短的纯文本,所以没有办法展示这一块的抓包记录。以后如果有时间可以试着做实验看看。
What’s new in TLSv1.3
从上图可以很清晰地看出,TLSv1.3 将之前的两次握手(Cipher Suite,Key Exchange)合并成为一次。这样做的好处就是减少了握手的次数,从而减少了握手所需要的时间。
此外,在接续旧有的会话时,TLSv1.3 采用了 0-RTT 的模式,即不需要握手,直接进行通信。
目前,TLSv1.3 还出于草案的状态,Nginx 等一众 HTTP Server 以及包括 Cloudflare 在内的多家 CDN 服务商已经不同程度地支持 TLS 1.3,最新版的 Chrome、Firefox 也已经支持 TLS 1.3(稍早的版本需要手动开启)。
当然,TLS 1.3 带来的新特性不止这些,且听下回分解。