在 TLS1.3 之前的 TLS 版本中, 可以通过 Session ID 字段来完成 Session Resumption.
Session ID: This is the identity of the session corresponding to this connection
那么具体实现如何呢,我们一起来看看。
流程
初始连接 (完整的握手后建立)
首先,在 ClientHello
和 ServerHello
都附带 Session ID
字段。
当客户端一次尝试与服务器通信时,它通常没有任何可以恢复的 tls session, 因此,需要进行一次完整的 tls 握手流程。 这个流程中以下点需要注意:
-
通常 ClientHello 中的 Session ID 设置为空。
-
ServerHello 中的 Session ID 不为空。
在这次握手成功之后,我们便有了一个可以在其他 tls 链接中使用的可恢复的 session 了。
用在当前连接中,即将被恢复的 session 可以是:
- 之前的 session(现在已经断开)
- 现有 session(连接成功,正在使用中),
- 或者从其他握手成功的 tls 中获取的 session。
完整的握手流程大体如下 (实际中可能略有不同):
Client Server
ClientHello (SessionID=empty) ----->
<----- ServerHello (SessionID=not empty)
Certificate
ServerKeyExchange
ServerHelloDone
ClientKeyExchange ----->
ChangeCipherSpec
Finished
<------ ChangeCipherSpec
Finished
如果想要从当前 session 建立其他 session, 需要保存以下信息:
- Session ID (ServerHello中)
- Master Secret (由当前 TLS 握手生成)
- CipherSuite (由当前 TLS 握手生成)
- Host name (只有将来连接到相同的 TLS server 时,从能使用当前信息进行 session恢复)
- 其他
从已有 session 建立一个新的 TLS 连接
从已有 session 建立新的连接的规则如下:
当 ClientHello
中的 Session ID
字段不为空时, 服务器便需要在自己的 session 的缓存中查找是否存在对应的 session:
- 当找到对应的 session, 并且服务器决定使用这个 session, 它便会把这个
Session ID
回复给客户端,来表明服务器端接受客户端的 session 恢复请求。 - 如果服务器没有找到缓存的 session, 或者不想恢复找到的 session, 它会给客户端回复一个全新的
Session ID
。 如果回复的Session ID
是空,表明当前 session‘ 不能被恢复。
恢复之后的 session 的 Cipher suite
应该和被恢复的 session 相同。
对于这个连接,有以下点需要注意:
ClientHello
中需要包含一个不为空的Session ID
, 表明想要恢复的 TLS session 状态。- 如果服务器回复的
ServerHello
中 包含了相同的Session ID
, 那么 session恢复成功。 否则,session 恢复失败。
通常情况下,session 恢复失败不会导致 TLS 连接的失败。 而是需要想第一个连接那么,进行完整的握手流程。
此时的握手流程大体如下 (实际中可能略有不同):
Client Server
ClientHello (SessionID=A) ----->
<----- ServerHello (SessionID=A)
ChangeCipherSpec
Finished
ChangeCipherSpec ----->
Finished
这里,session 恢复成功之后,使用对应的 MasterSecret, CipherSuite 对当前 TLS 通信过程中的数据进行加密解密
实例解析
1. 第一个 ClientHello
Handshake Protocol: Client Hello
Handshake Type: Client Hello (1)
Version: TLS 1.2 (0x0303)
Random: 6......373a7726385
Session ID Length: 0
......
Session ID: 空。 期待进行完整的 TLS 握手流程
2. 第一个 ServerHello
Handshake Protocol: Server Hello
Handshake Type: Server Hello (2)
Version: TLS 1.2 (0x0303)
Random: 1fc19c...01
Session ID Length: 32
Session ID: 756e6c6055fac1d3f4e23e19756d066dfb09bf847f6f16045feda2270cc7f307
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
....
Session ID: 服务器端生成了一个 session id, 用来标识当前 TLS session。
CipherSuite:这个属性也需要被记录,以便后续使用
3. Session Resumption 的 ClientHello
Handshake Protocol: Client Hello
Handshake Type: Client Hello (1)
Random: 64e32....5a5f
Session ID Length: 32
Session ID: 756e6c6055fac1d3f4e23e19756d066dfb09bf847f6f16045feda2270cc7f307
Cipher Suites Length: 116
Cipher Suites (58 suites)
....
Session ID: 这里,我们使用步骤2中相同的 Session ID来标识,我们想要从之前的那个 TLS session 中恢复, 以此建立一个新的 TLS session。
4. Session Resumption 的 ServerHello
Handshake Protocol: Server Hello
Handshake Type: Server Hello (2)
Version: TLS 1.2 (0x0303)
Random: 276c4e4....4e47524401
Session ID Length: 32
Session ID: 756e6c6055fac1d3f4e23e19756d066dfb09bf847f6f16045feda2270cc7f307
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
Compression Method: null (0)
Session ID: 可以看到,这里的 Session ID 与客户端发送的 ClientHello 中的 session id 相同, 标识此次 sesssion 恢复成功。
Leave a Reply