TLS Session Resumption: 基于 Session ID

在 TLS1.3 之前的 TLS 版本中, 可以通过 Session ID 字段来完成 Session Resumption.

Session ID: This is the identity of the session corresponding to this connection

那么具体实现如何呢,我们一起来看看。


流程


初始连接 (完整的握手后建立)


首先,在 ClientHelloServerHello 都附带 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:

  1. 当找到对应的 session, 并且服务器决定使用这个 session, 它便会把这个 Session ID 回复给客户端,来表明服务器端接受客户端的 session 恢复请求。
  2. 如果服务器没有找到缓存的 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 恢复成功。



Comments

Leave a Reply

Your email address will not be published. Required fields are marked *