最近的开发调试过程中涉及到了HTTPS发送与接收,遇到实际问题才发现对这部分尚属于一知半解。结合实际问题的解决过程来详细整理以下HTTPS通信过程。
需要调试的功能为BMC作为客户端向搭建好的Web服务器发送HTTPS请求,Web服务器负责接收处理发送过来的HTTPS请求。BMC的IP为100.6.100.224,Web服务器的IP为100.2.74.71。在BMC向Web服务器发送一条请求HTTPS请求,服务器成功接收到请求,返回成功信息。通过WireShark抓包这一过程,如下图所示:
从中可以看出,HTTPS通信过程分为两部分,首先进行TCP握手,然后进行TLS握手并发送信息。
1.1 TCP三次握手
前三个Wireshark数据包展示的就是TCP三次握手的过程,如下图所示:
1.1.1 第一次握手
第一次握手,客户端向服务器端发送SYN标志置位的报文,同时生成自己的随机初始序列号seq。数据包如下图所示。(这里客户端使用的seq直接使用了0,不太清楚为什么不是随机数)
1.1.2 第二次握手
第二次握手,服务器端向客户端发送SYN与ACK置位的报文,生成服务器端的随机初始序列号seq(这里服务器端的seq也直接使用了0),可以看到回复的报文中Ack的值为1(客户端seq+1),表示已收到客户端的SYN。
1.1.3 第三次握手
第三次握手,客户端向服务器端发送ACK置位的报文,报文中Ack的值为1(服务器端seq+1),服务器端收到后TCP连接就成功建立了。
1.2 TLS握手
TCP连接建立后,开始进入TLS握手阶段。TLS握手阶段数据包如下所示:
1.2.1 Client Hello
首先客户端向服务器端发送初始消息,内容包括支持的 TLS 版本,客户端随机数(Client Random,用于后续密钥生成)与支持的加密套件列表等,如下图所示。
1.2.2 Server Hello
服务器端会回复这一消息,如下图所示,回复的消息中包括选定的 TLS 版本(与客户端支持的版本一致),服务器随机数(Server Random,用于后续密钥生成)与选择的加密套件(从客户端发送的列表中选择),从图中可以看出服务器端选择了TLS v1.2,加密套件为TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
1.2.3 Certificate,Serverkey Exchange,Server Hello Done
下图的数据包中包括了Certificat,Serverkey Exchange与Server Hello Done三部分信息。服务器端发送其数字证书,包含服务器的公钥、证书颁发机构(CA)的签名以及域名等信息,供客户端验证身份,客户端则会验证证书是否由可信 CA 颁发、证书是否过期或被吊销以及证书中的域名与实际访问的域名是否一致。如下图所示,可以看到数据包中包含了证书信息
视选择的加密套件需要,服务器还会发送密钥交换参数(如 ECDHE 的公钥参数)以及用服务器私钥签名的数据(确保参数未被篡改):
最后服务器端还通知客户端,协商部分结束:
1.2.4 Client Key Exchange,Change Cipher Spec,Encrypted HandShake Message
客户端会生成一个预主密钥(pre-master secret),预主密钥用服务器的公钥加密后会被发送给服务器端。服务器会使用其私钥解密这个预主密钥,从而获得客户端的预主密钥。双方都拥有预主密钥之后,会使用之前的两个随机数(Client Hello中的Random与Server Hello中的Random)生成主密钥。到这里还没结束,TLS协议会使用PRF(伪随机函数)来从主密钥派生出一个用于加密的会话密钥和一个用于消息完整性和认证的MAC密钥。所有的密钥被正确生成和派生之后,客户端和服务器会通过交换完成的消息来确认彼此的身份,并确保所有的握手参数都是一致的,到此握手阶段才算完成。
1.2.5 Application Data, FIN
完成握手后,客户端就开始向服务器端发送数据。从数据包中可以看到,正常发送完毕之后,服务器端发送FIN标志置位的数据包断开连接,连接最后被断开了。