TCP / TLS 握手实践
参考文章:
TCP 建立连接的三次握手过程
TCP 三次握手基本上是计算机网络最常见的面试题了,更进一步的问题就是 HTTPS 和 HTTP 的加密机制。首先我们回顾一下三次握手的标准答案:
- 第一次:客户端向服务器发送 SYN 字段请求建立连接;客户端发送SYN包(seq=j)到服务器,并进入 SYN_SEND 状态,等待服务器确认;
- 第二次:服务器收到带有 SYN 的请求,通过返回带有 SYN + ACK 的数据包(ack = syn + 1),表示同意建立连接,并发送向客户端建立连接端请求,SYN 用来测试从服务器到客户端的连接通道是否畅通,此时服务器进入 SYN_RECV 状态;
- 第三次:客户端收到 SYN + ACK 后,回复服务器 ACK = SYN + 1,确认建立从客户端到服务器的连接;服务器收到后,双方都进入 ESTABLISHED 状态,表示连接建立成功。
三次握手是为了验证连接的双向数据传输是否能够正常工作。
TCP 握手实践
下面通过 WrieShark 来验证一下,这是一次请求 https://www.baidu.com 抓取到的网络请求信息:
| Step | source | destination | Protocol | Length | Info |
|---|---|---|---|---|---|
| 1 | 182.24.42.37 | 110.242.68.4 | TCP | 78 | 59115 → 443 [SYN] Seq=0 Win=65535 Len=0 MSS=1460 WS=64 TSval=4120303113 TSecr=0 SACK_PERM=1 |
| 2 | 110.242.68.4 | 182.24.42.37 | TCP | 78 | 443 → 59115 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=1380 WS=32 SACK_PERM=1 |
| 3 | 182.24.42.37 | 110.242.68.4 | TCP | 54 | 59115 → 443 [ACK] Seq=1 Ack=1 Win=262144 Len=0 |
在此次握手过程中,客户端 IP 为 182.24.42.37:59115;服务器 IP 为 110.242.68.4:443。进行了三个步骤:
- Step.1 ,客户端发起 TCP 请求,标识为 [SYN],Seq = 0;
- Step.2 ,服务器返回信息给客户端,标识为 [SYN, ACK],Seq = 0,Ack = 1;
- Step.3 ,客户端确认收到来自服务器消息,标识为 [ACK],Seq = 1,Ack = 1。
经过验证,的确是如经典答案所述。但这次是一个 HTTPS 请求 ,实际在 TCP 三次握手后,会建立 TLS 链接,下面介绍 TLS 的四次握手过程。
TLS 连接过程
上面请求的网址是 https://www.baidu.com,这是一次 HTTPS 请求。HTTPS 是由 HTTP 加上 TLS/SSL 协议构建的可进行加密传输、身份认证的网络协议,主要通过 数字证书、加密算法、非对称密钥等技术完成互联网数据传输加密,实现互联网传输安全保护。
TLS协议的优势是与高层的应用层协议(如HTTP、FTP、Telnet等)无耦合。应用层协议能透明地运行在TLS协议之上,由TLS协议进行创建加密通道需要的协商和认证。应用层协议传送的数据在通过TLS协议时都会被加密,从而保证通信的私密性。 -- from 百度百科
HTTPS 是经过 TLS/SSL 传输层安全性协议包装后的 HTTP 协议。
TLS 加密算法
单向加密过程
第一次握手
客户端 -> 服务器: Client Hello
客户端连接到服务器请求创建安全的连接,此时的消息携带客户端支持的加密算法列表信息和一个随机数,握手开始。
第二次握手
服务器 -> 客户端: Server Hello
服务器从客户端支持的加密算法列表中选出一种,通知客户端,此时服务器发出的消息携带一个服务器生成的随机数。
服务器 -> 客户端: Certificate
服务器向客户端发送数字证书,证书包含服务器的名称、CA 机构和服务器的公钥信息。
服务器 -> 客户端: Server Key Exchange
客户端无法自行计算预主密钥,需要服务器的参与,此时服务器发送带有密钥交换算法需要的额外数据,以便客户端可以计算出预主公钥。
服务器 -> 客户端: Server Hello Done
服务器发送 Server Hello Done ,并开始等待客户端的响应。
第三次握手
客户端 -> 服务器: Client Key Exchange
此时,客户端需要验证证书的有效性,验证通过取出公钥,生成一个随机数用公钥加密,发送给服务器,因为公钥是来自于服务器的证书中,所以服务器能够使用私钥进行解密。
计算预主密钥:此时,客户端开始计算预主密钥,服务器收到消息后,解析出随机数,也开始计算预主密钥,两个预主密钥用来后续的通信。
计算主密钥:通过预主密钥和服务器随机数、客户端随机数,计算出主密钥。
计算会话密钥:通过主密钥、服务器随机数、客户端随机数生成会话密钥。
这个最终的会话密钥包括:对称加密密钥(symmetric key)、消息认证码密钥(mac key)、初始化项量(iv key,只在必要时生成)。
客户端完成会话密钥计算后,发消息通知服务器:客户端已生成加密密钥,并切换到加密模式。
服务器收到该消息后,就同样地开始计算预主密钥、主密钥、生成会话密钥。
客户端 -> 服务器: Encrypted Handshake Message
将之前的握手数据做一个摘要,通过会话密钥加密(对称加密),发送 Encrypted Handshake Message 消息给服务器进行校验。
第四次握手
服务器 -> 客户端: Change Cipher Spec
服务器发消息通知客户端:服务器已生成加密密钥,请求客户端切换加密模式。
服务器 -> 客户端: Encrypted Handshake Message
将之前的握手数据做一个摘要,通过会话密钥加密(对称加密),发送 Encrypted Handshake Message 消息给客户端进行校验。
双向加密过程
双向加密过程前两次握手和单向加密过程相同,不在赘述。区别是第三次握手,客户端会先发送证书给服务器,服务器会验证客户端证书的合法性。
第三次握手
客户端 -> 服务器: Client Certificate
客户端将包含客户端公钥的数字证书发送给服务器。
服务器拿到客户端证书后,进行验证,验证通过获取到了客户端的公钥。
Client Certificate 消息是客户端收到 Server Hello Done 后,可以发送的第一条消息。仅当服务器要求了一个证书的情况下,客户端才发送 Client Certificate 消息,如果没有可用的合适证书,客户端必须发送一条不包含任何证书的 Client Certificate 消息。
客户端 -> 服务器: Client Key Exchange
此时,客户端需要验证证书的有效性,验证通过取出公钥,生成一个随机数用公钥加密,发送给服务器,因为公钥是来自于服务器的证书中,所以服务器能够使用私钥进行解密。
计算预主密钥:此时,客户端开始计算预主密钥,服务器收到消息后,解析出随机数,也开始计算预主密钥,两个预主密钥用来后续的通信。
计算主密钥:通过预主密钥和服务器随机数、客户端随机数,计算出主密钥。
计算会话密钥:通过主密钥、服务器随机数、客户端随机数生成会话密钥。
这个最终的会话密钥包括:对称加密密钥(symmetric key)、消息认证码密钥(mac key)、初始化项量(iv key,只在必要时生成)。
客户端完成会话密钥计算后,发消息通知服务器:客户端已生成加密密钥,并切换到加密模式。
此时的服务器
服务器收到该消息后,与单向加密不同的是,会额外使用客户端的公钥来计算预主密钥,进一步计算出会话密钥。
就同样地开始计算预主密钥、主密钥、生成会话密钥。
客户端 -> 服务器: Encrypted Handshake Message
将之前的握手数据做一个摘要,通过会话密钥加密(对称加密),发送加密消息给服务器进行校验。
后续步骤与单向加密相同。
TLS 协议栈
TLS 由多种协议一起组成,是在 TCP 传输层之上的传输层安全性协议,这些组成部分包括:
- Handshake Protocol,握手协议,用于建立 TLS 连接。
- Change Cipher Spec Protocol,密钥规格变更协议,用于协商客户端与服务器的密钥处理。
- Application Data Protocol,应用数据协议,例如 HTTP 。
- Alert Protocol,警报协议,用于表示关闭信息和错误信息。
- Record Layer,记录层,用于日志记录。
Wireshark TLS 握手实践
在完成 TCP 三次握手后,连接建立成功,开始通过 TLSv1.2 安全传输层协议对消息进行加密:
| Step | source | destination | Protocol | Length | Info | Record Layer |
|---|---|---|---|---|---|---|
| 1 | 182.24.42.37 | 110.242.68.4 | TLSv1.2 | 571 | Client Hello | Handshake Protocol: Client Hello |
| 2 | 110.242.68.4 | 182.24.42.37 | TLSv1.2 | 1414 | Server Hello, | Handshake Protocol: Server Hello |
| 3 | 110.242.68.4 | 182.24.42.37 | TLSv1.2 | 1215 | Certificate, Server Key Exchange, Server Hello Done | Handshake Protocol: Certificate Handshake Protocol: Server Key Exchange Handshake Protocol: Server Hello Done |
| 4 | 182.24.42.37 | 110.242.68.4 | TLSv1.2 | 105 | Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message | Handshake Protocol: Client Key Exchange Change Cipher Spec Protocol: Change Cipher Spec Handshake Protocol: Encrypted Handshake Message |
| 5 | 182.24.42.37 | 110.242.68.4 | TLSv1.2 | 1154 | Application Data | Application Data Protocol: http-over-tls // 此时已经是加密消息了 |
| 6 | 110.242.68.4 | 182.24.42.37 | TLSv1.2 | 280 | New Session Ticket, Change Cipher Spec, Encrypted Handshake Message | Handshake Protocol: New Session Ticket Change Cipher Spec Protocol: Change Cipher Spec Handshake Protocol: Encrypted Handshake Message |
| 7 | 110.242.68.4 | 182.24.42.37 | TLSv1.2 | 1262 | Application Data | Application Data Protocol: http-over-tls |
第一次握手
Step.1 Client Hello
客户端向服务器发送请求,发送 TLS 版本,发送客户端支持的加密算法列表和一个随机数:
第二次握手
Step.2 Server Hello
服务器返回消息给客户端,握手协议:在客户端提供的加密算法中选择一种进行加密后,返回服务器端随机数和选择的算法以及版本信息:
Step.3 Certificate, Server Key Exchange, Server Hello Done
Certificate,服务器向客户端发送证书给客户端:
Server Key Exchange,传递密钥交换算法参数信息给客户端:
Server Hello Done 服务器将之前所有的握手数据做一个摘要,供服务器校验。
第三次握手
Step.4 Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message
Step.4,客户端回复握手消息:
Client Key Exchange,将加密算法参数信息(生成客户端公钥信息)发送给服务器:
Change Cipher Spec 通知服务器切换加密模式:
Encrypted Handshake Message, 生成会话密钥后通知服务器:
Step.5 Application Data
此时客户端到服务器到链路已经打通,发送一条加密数据消息供服务器校验:
第四次握手
Step.6 New Session Ticket, Change Cipher Spec, Encrypted Handshake Message
New Session Ticket,服务器返回新的 session ticket,通知客户端切换加密算法,并验证会话密钥后返回消息给客户端:
Change Cipher Spec,通知客户端切换加密模式:
Encrypted Handshake Message,服务器确认完成握手:
Step.7 Application Data
服务器到客户端的链路打通,确认协议为 http-over-tls ,发送一条消息供客户端校验。
Note
TLS 协议对数据进行了加密,所以这里看不到 HTTP 协议的相关信息(也就是 Application Data 中的信息),需要通过密钥解密,才能看见此次请求中 HTTP 协议的内容,下面是个解密后的例子:
总结
TCP 连接建立过程
- 第一次:客户端向服务器发送 SYN 字段请求建立连接;客户端发送SYN包(seq=j)到服务器,并进入 SYN_SEND 状态,等待服务器确认;
- 第二次:服务器收到带有 SYN 的请求,通过返回带有 SYN + ACK 的数据包(ack = syn + 1),表示同意建立连接,并发送向客户端建立连接端请求,SYN 用来测试从服务器到客户端的连接通道是否畅通,此时服务器进入 SYN_RECV 状态;
- 第三次:客户端收到 SYN + ACK 后,回复服务器 ACK = SYN + 1,确认建立从客户端到服务器的连接;服务器收到后,双方都进入 ESTABLISHED 状态,表示连接建立成功。
TLS 连接建立过程
单向验证
第一次握手
客户端 -> 服务器: Client Hello
客户端连接到服务器请求创建安全的连接,此时的消息携带客户端支持的加密算法列表信息和一个随机数,握手开始。
第二次握手
服务器 -> 客户端: Server Hello
服务器从客户端支持的加密算法列表中选出一种,通知客户端,此时服务器发出的消息携带一个服务器生成的随机数。
服务器 -> 客户端: Certificate
服务器向客户端发送数字证书,证书包含服务器的名称、CA 机构和服务器的公钥信息。
服务器 -> 客户端: Server Key Exchange
客户端无法自行计算预主密钥,需要服务器的参与,此时服务器发送带有密钥交换算法需要的额外数据,以便客户端可以计算出预主公钥。
服务器 -> 客户端: Server Hello Done
服务器发送 Server Hello Done ,并开始等待客户端的响应。
第三次握手
客户端 -> 服务器: Client Key Exchange
此时,客户端需要验证证书的有效性,验证通过取出公钥,生成一个随机数用公钥加密,发送给服务器,因为公钥是来自于服务器的证书中,所以服务器能够使用私钥进行解密。
计算预主密钥:此时,客户端开始计算预主密钥,服务器收到消息后,解析出随机数,也开始计算预主密钥,两个预主密钥用来后续的通信。
计算主密钥:通过预主密钥和服务器随机数、客户端随机数,计算出主密钥。
计算会话密钥:通过主密钥、服务器随机数、客户端随机数生成会话密钥。
这个最终的会话密钥包括:对称加密密钥(symmetric key)、消息认证码密钥(mac key)、初始化项量(iv key,只在必要时生成)。
客户端完成会话密钥计算后,发消息通知服务器:客户端已生成加密密钥,并切换到加密模式。
服务器收到该消息后,就同样地开始计算预主密钥、主密钥、生成会话密钥。
客户端 -> 服务器: Encrypted Handshake Message
将之前的握手数据做一个摘要,通过会话密钥加密(对称加密),发送 Encrypted Handshake Message 消息给服务器进行校验。
第四次握手
服务器 -> 客户端: Change Cipher Spec
服务器发消息通知客户端:服务器已生成加密密钥,请求客户端切换加密模式。
服务器 -> 客户端: Encrypted Handshake Message
将之前的握手数据做一个摘要,通过会话密钥加密(对称加密),发送 Encrypted Handshake Message 消息给客户端进行校验。
双向验证
双向加密过程前两次握手和单向加密过程相同,不在赘述。区别是第三次握手,客户端会先发送证书给服务器,服务器会验证客户端证书的合法性。
第三次握手
客户端 -> 服务器: Client Certificate
客户端将包含客户端公钥的数字证书发送给服务器。
服务器拿到客户端证书后,进行验证,验证通过获取到了客户端的公钥。
Client Certificate 消息是客户端收到 Server Hello Done 后,可以发送的第一条消息。仅当服务器要求了一个证书的情况下,客户端才发送 Client Certificate 消息,如果没有可用的合适证书,客户端必须发送一条不包含任何证书的 Client Certificate 消息。
客户端 -> 服务器: Client Key Exchange
此时,客户端需要验证证书的有效性,验证通过取出公钥,生成一个随机数用公钥加密,发送给服务器,因为公钥是来自于服务器的证书中,所以服务器能够使用私钥进行解密。
计算预主密钥:此时,客户端开始计算预主密钥,服务器收到消息后,解析出随机数,也开始计算预主密钥,两个预主密钥用来后续的通信。
计算主密钥:通过预主密钥和服务器随机数、客户端随机数,计算出主密钥。
计算会话密钥:通过主密钥、服务器随机数、客户端随机数生成会话密钥。
这个最终的会话密钥包括:对称加密密钥(symmetric key)、消息认证码密钥(mac key)、初始化项量(iv key,只在必要时生成)。
客户端完成会话密钥计算后,发消息通知服务器:客户端已生成加密密钥,并切换到加密模式。
此时的服务器
服务器收到该消息后,与单向加密不同的是,会额外使用客户端的公钥来计算预主密钥,进一步计算出会话密钥。
就同样地开始计算预主密钥、主密钥、生成会话密钥。
客户端 -> 服务器: Encrypted Handshake Message
将之前的握手数据做一个摘要,通过会话密钥加密(对称加密),发送加密消息给服务器进行校验。
后续步骤与单向加密相同。