rsa前后端加密流程_HTTPS 温故知新(三)——直观感受 TLS 握手流程(中)

Go语言中文网,致力于每日分享编码、开源等知识,欢迎关注我,会有意想不到的收获!

接着上篇:HTTPS 温故知新(三)——直观感受 TLS 握手流程(上)

四. 直观感受 TLS 1.2 首次握手流程

至此,TLS 1.2 首次握手的所有细节都已经分析完了。这一节让我们小结一下上面的流程,并用 Wireshark 直观感受一下 TLS 1.2 协议。

首先是基于 RSA 密钥协商算法的首次握手:

2d58ceb21ddfbce3295e652defbbeb3f.png

握手开始,Client 先发送 ClientHello ,在这条消息中,Client 会上报它支持的所有“能力”。client_version 中标识了 Client 能支持的最高 TLS 版本号;random 中标识了 Client 生成的随机数,用于预备主密钥和主密钥以及密钥块的生成,总长度是 32 字节,其中前 4 个字节是时间戳,后 28 个字节是随机数;cipher_suites 标识了 Client 能够支持的密码套件。extensions 中标识了 Client 能够支持的所有扩展。

关于 extensions 本篇文章涉及的少,因为笔者打算把 TLS 1.2 和 TLS 1.3 中涉及到的 extensions 都整理到一篇文章中,在这篇握手的流程中没有详细分析。extensions 更加详细的分析请见 《HTTPS 温故知新(六) —— TLS 中的 Extensions》

Server 在收到 ClientHello 之后,如果能够继续协商,就会发送 ServerHello,否则发送 Hello Request 重新协商。在 ServerHello 中,Server 会结合 Client 的能力,选择出双方都支持的协议版本以及密码套件进行下一步的握手流程。server_version 中标识了经过协商以后,Server 选出了双方都支持的协议版本。random 中标识了 Server 生成的随机数,用于预备主密钥和主密钥以及密钥块的生成,总长度是 32 字节,其中前 4 个字节是时间戳,后 28 个字节是随机数;cipher_suites 标识了经过协商以后,Server 选出了双方都支持的密码套件。extensions 中标识了 Server 处理 Client 的 extensions 之后的结果。

当协商出了双方都能满足的密钥套件,根据需要 Server 会发送 Certificate 消息。Certificate 消息会带上 Server 的证书链。Certificate 消息的目的一是为了验证 Server 身份,二是为了让 Client 根据协商出来的密码套件从证书中获取 Server 的公钥。Client 拿到 Server 的公钥和 server 的 random 会生成预备主密钥。

由于密钥协商算法是 RSA,需要 Server 在发送完 Certificate 消息以后就直接发送 ServerHelloDone 消息了。

Client 收到 ServerHelloDone 消息以后,会开始计算预备主密钥,计算出来的预备主密钥会经过 RSA/ECDSA 算法加密,并通过 ClientKeyExchange 消息发送给 Server。RSA 密码套件的预备主密钥是 48 字节。前 2 个字节是 client_version,后 46 字节是随机数。Server 收到 ClientKeyExchange 消息以后就会开始计算主密钥和密钥块了。同时 Client 也会在自己本地算好主密钥和密钥块。

有些人会说“主密钥和会话密钥”,这里的会话密钥和密钥块是相同的意思。主密钥是由预主密钥、客户端随机数和服务器随机数通过 PRF 函数来生成;会话密钥是由主密钥、客户端随机数和服务器随机数通过 PRF 函数来生成。

会话密钥 = key_block = 密钥块,这三者的意思是一样的,只是翻译不同罢了。

Client 发送完 ClientKeyExchange 消息紧接着还会继续发送 ChangeCipherSpec 消息和 Finished 消息。Server 也会回应 ChangeCipherSpec 消息和 Finished 消息。如果 Finished 消息校验完成以后,代表握手最终成功。

再来看看基于 DH 密钥协商算法的首次握手:

ba0252a58bda2eb2ecdc2e535104b753.png

基于 DH 密钥协商算法和基于 RSA 密码协商的区别在 Server 和 Client 协商 DH 参数上面。这里只说明一下 DH 密钥协商过程比 RSA 多的几步,其他的流程和 RSA 的流程基本一致。

在 Server 发送完 Certificate 消息以后,还会继续发送 ServerKeyExchange 消息,在这条消息里面传递 DH 参数。

另外一个不同点在于 ClientKeyExchange 消息中传递给 Server 预备主密钥长度不是 48 字节。基于 DH/ECDH 算法的协商密钥长度取决于 DH/ECDH 算法的公钥。

为了让读者能更加直观的理解 TLS 1.2 的流程,笔者用 Wireshark 抓取了 Chrome 和笔者博客 TLS 握手中的网络包。结合 Wireshark 的抓包分析,让我们更加深入的理解 TLS 1.2 握手吧。下面的例子以 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 密码套件为例:

8d271cb255fde9dd574fa1097781baa3.png

上面这是一次从 TLS 握手开始到 TCP 4 次挥手完整的过程。这里我们重要关注 protocol = TLS 1.2 的所有消息。整体流程和上面分析的基于 DH 密钥交换算法的是一致的。在 TCP 4 次挥手之前,TLS 层会先收到 Close Notify 的 Alert 消息。

读到这里能有读者有疑问,为什么经过 TLS 加密以后的上层数据会以明文展示在抓包中?HTTPS 不安全?这里需要解释一下,因为笔者利用 export SSLKEYLOGFILE=/Users/XXXX/sslkeylog.log把 ECDHE 协商的密钥保存成 log 文件了,解析上层 HTTP/2 的加密包的时候就可以利用 log 中的 TLS key 进行解密。上图中绿色的部分,就是通过解密出来得到的 HTTP/2 的解密内容。具体这块内容笔者会在 HTTP/2 相关的文章里面会提一提,这里读者就认为是笔者利用某些手段解析出了 HTTPS 加密的内容即可。

接下来一条条的看看网络是如何传输数据包的。从 ClientHello 开始。

0f56f53d2c78ed9035d08412e0fefed9.png

从 TLS 1.2 Record Layer 的 Length 字段中我们可以看到 TLS 记录层的这条 TLS 握手消息长度是 512 字节,其中 ClientHello 消息中占 508 字节。ClientHello 中标识了 Client 最高支持的 TLS 版本是 TLS 1.2 (0x0303)。Client 支持的密码套件有 17 种,优先支持的是 TLS_AES_128_GCM_SHA256 。Session ID 的长度是 32 字节,这里不为空。压缩算法是 null。signature_algorithms 中标识了 Client 支持 9 对数字签名算法。

默认情况下 TLS 压缩都是关闭的,因为 CRIME 攻击会利用 TLS 压缩恢复加密认证 cookie,实现会话劫持,而且一般配置 gzip 等内容压缩后再压缩 TLS 分片效益不大又额外占用资源,所以一般都关闭 TLS 压缩。

74458a4fcd959db9ec866ff5e0530eb4.png

ClientHello 中发送了 status_request 扩展,查询 OCSP 封套消信息。发送了 signed_certificate_timestamp 扩展,查询 SCT 信息。发送了 application_layer_protocol_negotiation (ALPN)扩展,询问服务端是否支持 HTTP/2 协议。supported_group 扩展里面标识了 Client 中支持的椭圆曲线。SessionTicket TLS 扩展表明了 Client 支持基于 Session Ticket 的会话恢复。

再看看 ServerHello 消息。

a128f5bd1deeecbd29e8881667620e5f.png

从 TLS 1.2 Record Layer 的 Length 字段中我们可以看到 TLS 记录层的这条 TLS 握手协议消息长度是 82 字节,其中 ServerHello 消息中占 78 字节。Server 选择用 TLS 1.2 版本与 Client 进行接下来的握手流程。Server 与 Client 协商出来的密码套件是 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384。

Server 支持 HTTP/2,在 ALPN 扩展中进行了回复。

e18eaf71295136611974d696bdc17435.png

从 TLS 1.2 Record Layer 的 Length 字段中我们可以看到 TLS 记录层的这条 TLS 握手消息长度是 2544 字节,其中 Certificate 消息中占 2540 字节,Certificates 证书链包含 2 张证书,Server 实体证书 1357 字节,中间证书 1174 字节。中间证书是 Let's Encrypt 签发的。两张证书都是用 sha256WithRSAEncryption 签名算法进行签名的。

ceacaacbad3781d6f7003b8f829044d4.png

从 TLS 1.2 Record Layer 的 Length 字段中我们可以看到 TLS 记录层的这条 TLS 握手协议消息长度是 535 字节,其中 Certificate Status 消息中占 531 字节。Server 将 OCSP 的 response 发送给 Client。

从 TLS 1.2 Record Layer 的 Length 字段中我们可以看到 TLS 记录层的这条 TLS 握手协议消息长度是 116 字节,其中 ServerKeyExchange 消息中占 112 字节。由于协商出来的是 ECDHE 密钥协商算法,所以 Server 需要把 ECDH 的参数和公钥通过 ServerKeyExchange 消息发给 Client。这里 ECDHE 使用的 ECC 命名曲线是 x25519 。Server 的公钥是 (62761b5……),签名算法是 ECDSA_secp256r1_SHA256 。签名值是 (3046022……)。

ServerHelloDone 消息结构很简单,见上图。

68383a183de5a8edf0828757867baf7e.png

由于是 ECDHE 协商算法,所以 Client 需要发送 ECC DH 公钥,对应的公钥值是 (1e58cf……)。公钥长度 32 字节。

ChangeCipherSpec 消息结构很简单,发送这条消息是为了告诉 Server ,Client 可以使用 TLS 记录层协议进行密码学保护了。第一条进行密码学保护的消息是 Finished 消息。

Finished 消息结构很简单,见上图。

b3461fb88dbb3a3712eaa1727ef84a1b.png

Server 如果只是 SessionTicket,那么会生成新的 NewSessionTicket 返给 Client,然后同样返回 ChangeCipherSpec 消息和 Finished 消息。

90e585182c4b5314684e140384758cd7.png

当页面关闭的时候,Server 会给 Client 发送 TLS Alert 消息,这条消息里面的描述就是 Close Notify。同时 Server 会发送 FIN 包开始 4 次挥手。

五. TLS 1.2 会话恢复

Client 和 Server 只要一关闭连接,短时间内再次访问 HTTPS 网站的时候又需要重新连接。新的连接会造成网络延迟,并消耗双方的计算能力。有没有办法能复用之前的 TLS 连接呢?办法是有的,这就涉及到了 TLS 会话复用机制。

当 Client 和 Server 决定继续一个以前的会话或复制一个现存的会话(取代协商新的安全参数)时,消息流如下:

Client 使用需要恢复的当前会话的 ID 发送一个 ClientHello。Server 检查它的会话缓存以进行匹配。如果匹配成功,并且 Server 愿意在指定的会话状态下重建连接,它将会发送一个带有相同会话 ID 值的 ServerHello 消息。这时,Client 和 Server 必须都发送 ChangeCipherSpec 消息并且直接发送 Finished 消息。一旦重建立完成,Client 和 Server 可以开始交换应用层数据(见下面的流程图)。如果一个会话 ID 不匹配,Server 会产生一个新的会话 ID,然后 TLS Client 和 Server 需要进行一次完整的握手。

C

 Client Server ClientHello --------> ServerHello [ChangeCipherSpec]  Application Data  Application Data 

Session ID 由服务器端支持,协议中的标准字段,因此基本所有服务器都支持,服务器端保存会话 ID 以及协商的通信信息,占用服务器资源较多。

1. 基于 Session ID 的会话恢复

当 Client 通过一次完整的握手,与 Server 建立了一次完整的 Session,Server 会记录这次 Session 的信息,以备恢复会话的时候使用:

  • 会话标识符(session identifier):
  • 每个会话的唯一标识符
  • 对端的证书(peer certificate):
  • 对端的证书,一般为空
  • 压缩算法(compression method):
  • 一般不启用
  • 密码套件(cipher spec):
  • Client 和 Server 协商共同协商出来的密码套件
  • 主密钥(master secret):
  • 每个会话都会保存一份主密钥,注意不是预备主密钥。(读者可以想想为什么,如果还是想不通,见 《HTTPS 温故知新(五) —— TLS 中的密钥计算》)
  • 会话可恢复标识(is resumable):
  • 标识会话是否可恢复

当 Server 保存了以上的信息,可以再次计算出 TLS 记录层需要的 security parameters 加密参数,从而加密应用数据。

基于 Session ID 会话恢复的流程如下:

 Client Server ClientHello --------> ServerHello [ChangeCipherSpec]  Application Data  Application Data 
5c7d4216077d6d85c21d150352c69021.png

Client 发现请求的网站是之前请求过的,即内存中存在 Session ID,那么再次建立连接的时候会在 ClientHello 中附带与网站对应的 Session ID。Server 的内存中会保存一份 Session Cache 的字典,key 是 Session ID,value 是会话信息。Server 收到 ClientHello 以后,根据传过来的 Session ID 查看是否有相关的会话信息,如果有,就会允许 Client 进行会话恢复,直接发送 ChangeCipherSpec 和 Finished 消息。如果没有相关的会话信息,就会开始一次完整的握手,并在 ServerHello 中生成新的 Session ID 返回给 Client。Client 收到 Server 发来的 ChangeCipherSpec 和 Finished 消息,代表会话恢复成功,也发送 ChangeCipherSpec 和 Finished 消息作为回应。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值