HTTPS - 揭秘 TLS 1.2 协议完整握手过程
关注并将「趣谈前端」设为星标
定期推送技术干货/优秀开源/技术思维
HTTPS 是建立在 SSL/TLS 传输层安全协议之上的一种 HTTP 协议,相当于 HTTPS = HTTP + SSL/TLS
。第一篇文章 “HTTPS - 通俗易懂的阐述 HTTPS 协议,解决面试难题” 更多是理论上的一些阐述,能解决一些面试及常见问题,例如 “SSL/TLS” 的关系是什么?文中都有介绍。本文通过对一次 TLS 握手过程的数据抓包分析做为切入点,希望能进一步的帮助大家理解 HTTPS 原理。
TLS 协议
TLS 是一种密码学协议,保证了两个端点之间的会话安全,一种最好的学习方法是使用抓包工具,捕获网络数据包,基于这些真实的数据包能够有一些直观的感受,例如:Wireshark,它可以捕获 HTTP、TCP、TLS 等各种网络协议数据包,是我们学习的好工具。
TLS 定义了四个核心子协议:握手协议 (handshake protocol)、密钥规格变更协议 (change cipher spec protocol)、应用数据协议 (application data protocol) 和警报协议 (alert protocol),这里最主要、最复杂是“握手协议”,协商对称密码就是在该协议中完成的。
图片来源:https://hpbn.co/assets/diagrams/9873c7441be06e0b53a006aac442696c.svg
握手过程图示
参考 “网络协议那些事儿 - 如何抓包并破解 HTTPS 加密数据?”,本文是抓取的 www.imooc.com 网站数据包,基于 TLS v1.2 协议未对数据包做解密处理。
下图展示了 HTTPS 链接建立、TLS 握手协议里参数传递、证书验证、协商对称密钥的过程,更详细的内容,下文会介绍。
握手协议
握手协议是 TLS 协议中最复杂的一部分,在这个过程中双方会协商链接参数(TLS 版本号、随机数等)并完成身份验证。里面可能会存在几种情况:完整握手,对服务器进行身份验证、恢复之前的会话采用的简短握手、对客户端和服务器都进行身份验证握手,下文以完整握手为例。
在建立 TCP 链接之后,每一个 TLS 链接都会以握手协议开始,完整握手是客户端与服务器之前未建立会话,在第一次会话时会经历一次完整的握手。
Client Hello
在一次新的握手协议中,客户端(浏览器)首先发出的一条消息是 “Client Hello”,告诉服务器我将给你传递这些数据:
Version:客户端支持的最佳协议版本号。 Random:客户端提供给服务器的随机数,在每次握手中都会重新生成,这个随机数用于后续生成密钥。 Session ID:会话 ID 在第一次链接时该字段是空的,表示客户端并不希望恢复某个已存在的会话。 Cipher Suites:客户端所支持的所有秘密套件,按优先级顺序排列。
Handshake Protocol: Client Hello
Handshake Type: Client Hello (1)
Length: 223
Version: TLS 1.2 (0x0303)
Random: b0fcb3aca27c6de8b0e4f146b92d33f24e6a671e62f8f6f669aabbfc19bb4326
Session ID Length: 0
Cipher Suites Length: 92
Cipher Suites (46 suites)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (0xc028)
...
Server Hello
“Server Hello” 是服务器在收到客户端 “Client Hello” 之后的一个回应,告诉客户端服务器的协议版本、服务器也会给出一个随机数 Random 用于后续生成密钥,Cipher Suite 是从客户端 “Client Hello” 消息的 Cipher Suites 里选择的一个密码套件。
Handshake Protocol: Server Hello
Handshake Type: Server Hello (2)
Length: 89
Version: TLS 1.2 (0x0303)
Random: 616d836f609800aaa1713462f61d50cc6472c45b54c0ac58dd52b9db4d555f6f
Session ID Length: 32
Session ID: 279fb99351526e29a4ce41af4cbff5575933e5c45dff7a2016a16cdf414f22c2
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
了解密码套件构成
Certificate, Server Key Exchange, Server Hello Done
在 “Server Hello” 之后,服务器紧跟随着发出 “Certificate, Server Key Exchange, Server Hello Done” 这三个消息告知客户端。
Certificate(发送服务器证书信息到客户端)
证书信息,典型的 Certificate 消息用于携带服务器 X.509 证书链,一个接一个组合而成,主证书第一个,之后中间证书和根证书,服务器的公钥也包含在证书信息中。
Handshake Protocol: Certificate
Handshake Type: Certificate (11)
Length: 2781
Certificates Length: 2778
Certificates (2778 bytes)
Certificate Length: 1407
Certificate: 3082057b30820463a0030201020210040f1f824b17ca53814dc5c6f4c6a0a8300d06092a… (id-at-commonName=*.imooc.com)
Certificate Length: 1365
Certificate: 3082055130820439a003020102021007983603ade39908219ca00c27bc8a6c300d06092a… (id-at-commonName=RapidSSL TLS DV RSA Mixed SHA256 2020 CA-1,id-at-organizationName=DigiCert Inc,id-at-countryName=US)
这个证书链在浏览器地址栏点击域名前面的 “小锁”,可看到如下信息,最上面是根证书、中间(RapidSSL)是中级证书颁发机构、*.imooc.com 这个是 CA 颁发给我们的域名证书。
Server Key Exchange(密钥交换)
“Server Key Exchange” 消息是携带密钥交换算法需要的额外数据,目的是计算主密钥需要的另一个值:“预主密钥(premaster secret)”。
不同的算法套件对应的消息内容也是不同的,下面 EC Diffie-Hellman(简称 ECDHE)就是密钥交换算法,这个对应 “Server Hello” 消息中选择的密码套件 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
中的 ECDHE
。
下面 Server Params 中的 Curve Type 表示曲线类型,本次选中的椭圆曲线名称为 named_curve:secp256r1,再确定基点 G,此时还会选择生成一个随机数做为服务端椭圆曲线的私钥,存放到本地,再根据基点 G 和椭圆曲线的私钥计算出椭圆曲线公钥(这里的椭圆曲线公/私钥都是临时的,只对本次链接生效),名字为 Pubkey 传递给客户端。
为了确保椭圆曲线公钥信息不被篡改,将 Server Params 与客户端和服务器随机值连在一起使用私钥签名,客户端从证书中获得服务器的公钥,就可验证是否来自服务器。客户端和服务器的随机值对于一次握手是唯一的,这也意味着攻击者无法重复利用该签名。
Handshake Protocol: Server Key Exchange
Handshake Type: Server Key Exchange (12)
Length: 329
EC Diffie-Hellman Server Params
Curve Type: named_curve (0x03)
Named Curve: secp256r1 (0x0017)
Pubkey Length: 65
Pubkey: 049c1c4eaa2ab8ae7b54482efc5d07e2b191174d804d660be07ded253c86f9bc5cd24f34…
Signature Algorithm: rsa_pkcs1_sha512 (0x0601)
Signature Hash Algorithm Hash: SHA512 (6)
Signature Hash Algorithm Signature: RSA (1)
Signature Length: 256
Signature: 5b9b1a750f0168f0a57852b4a77c14c351c5b97d7eb4a470fa8e3cf9e385cf7ac16f056f…
不同的密钥交换算法,生成预主密钥的方式也不同,我们这里的示例以 ECDHE 为主,还有一种密钥交换算法是 RSA,它的密钥交换过程很简单,由客户端生成预主密钥,为 46 字节的随机数,使用服务器的公钥加密,经过“Client Key Exchange” 消息发送到服务端,服务端再用私钥就可解密出这个预主密钥。
基于 RSA 的密钥交换算法被认为存在严重的漏洞威胁,任何能够接触到私钥的人(例如,由于政治、贿赂、强行进入等)都可恢复预主密钥,进而构建相同的主密钥,最终密钥泄漏就可解密之前记录的所有流量了。这种密钥交换算法正在被支持前向保密保密的其它算法替代,例如,我们示例中的 ECDHE 算法在密钥交换时,每个链接使用的主密钥相互独立,如果出现问题也只是影响到当前会话,不能用于追溯解密任何其它的流量。
Server Hello Done
“Server Hello Done” 表示服务器已将握手消息需要的数据都发送完毕。之后就是等待客户端的回应。
Handshake Protocol: Server Hello Done
Handshake Type: Server Hello Done (14)
Length: 0
Client Key Exchange(客户端发送给服务器的密钥交换信息)
“Client Key Exchange” 的消息也是携带密钥交换需要的额外数据,不过这一次是客户端发送给服务端的,Client Params 里面提供了客户端生成的临时椭圆曲线公钥信息。
Handshake Protocol: Client Key Exchange
Handshake Type: Client Key Exchange (16)
Length: 66
EC Diffie-Hellman Client Params
Pubkey Length: 65
Pubkey: 04c64110c2838d112d8fbc8a85a2c2b3b596e70d6ff9198330801df93ce9737432eeabe6…
客户端验证证书和计算密钥
现在一次 TCP 往返结束了,客户端拿到了服务器的证书、Server Random、Server Params,现在客户端需要验证证书合法性和计算一些加密信息。
验证服务器发来的证书合法性
客户端收到服务器的响应信息,验证证书的合法性,可回顾上一节 深入浅出 HTTPS 原理篇。如果证书校验通过继续往下走。
计算预主密钥
上面也提了,在 “Server Key Exchange” 消息中,服务器对 Server Params 用私钥做了签名,客户端要从证书中获得服务器公钥,验证参数是否来自期望的服务器,这也是身份验证。
身份验证成功之后,得到 Server Params 参数,而 Server Params 参数里包含了 “服务器密钥交换消息” 中生成的临时公钥、secp256r1 椭圆曲线算法,现在客户端使用 secp256r1 算法用这个临时公钥和客户端自己生成的临时私钥相乘计算出预主密钥(premaster secret)。
计算主密钥
现在客户端手里已经有了 Client Random、Server Random、Premaster Secret 三个随机参数,调用 PRF 伪随机函数函数生成 48 字节(384 位)主密钥。
master_secret = PRF(pre_master_secret, "master secret",
ClientHello.random + ServerHello.random)
构建会话密钥
上面的主密钥并不是最终的会话密钥,最终的会话密钥使用 PRF 伪随机函数传入主密钥、客户端随机数、服务端随机数生成。
key_block = PRF(master_secret, "key expansion", server_random + client_random)
这个最终的会话密钥包括:对称加密密钥(symmetric key)、消息认证码密钥(mac key)、初始化项量(iv key,只在必要时生成)。
客户端发出 Change Cipher Spec, Encrypted Handshake Message
当客户端完成密钥计算操作后,还要给服务器发送切换加密模式、验证会话密码消息。
Change Cipher Spec
“Change Cipher Spec” 消息表示客户端已生成加密密钥,并切换到加密模式。
TLSv1.2 Record Layer: Change Cipher Spec Protocol: Change Cipher Spec
Content Type: Change Cipher Spec (20)
Version: TLS 1.2 (0x0303)
Length: 1
Change Cipher Spec Message
注意:“Change Cipher Spec” 不属于握手协议,它是另一种密钥规格变更协议。
Encrypted Handshake Message
这个是将之前所有的握手数据做一个摘要,再用最后协商好的对称加密算法对数据做加密,通过 “Encrypted Handshake Message” 消息发送到服务器进行校验,这个对称加密密钥是否成功。
TLSv1.2 Record Layer: Handshake Protocol: Encrypted Handshake Message
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: 60
Handshake Protocol: Encrypted Handshake Message
服务器计算密钥
服务器在收到客户端 “Client Key Exchange” 消息后,这时可以拿到 Client Random、Server Random、Client Params,先计算出预主密钥后,再分别计算出主密钥和最终的会话密钥,这块可参考客户端计算密钥一样的。
服务器发出 Change Cipher Spec, Encrypted Handshake Message
Change Cipher Spec
服务器发出 “Change Cipher Spec” 消息告诉客户端,服务端已生成密钥,请求客户端切换加密模式。
TLSv1.2 Record Layer: Change Cipher Spec Protocol: Change Cipher Spec
Content Type: Change Cipher Spec (20)
Version: TLS 1.2 (0x0303)
Length: 1
Change Cipher Spec Message
Encrypted Handshake Message
“Encrypted Handshake Message” 这条消息也是服务器对握手的所有数据用协商好的对称加密算法加密,供客户端校验。
如果对抓取后的报文做解密,这里看到的是 “Finished” 消息。
TLSv1.2 Record Layer: Handshake Protocol: Encrypted Handshake Message
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: 40
Handshake Protocol: Encrypted Handshake Message
应用数据协议
整个握手过程完毕之后,我们会看到应用数据协议 “Application Data Protocol: http-over-tls”,之后我们的客户端/服务端建立一个安全通信隧道,就可以发送应用程序数据了。
TLSv1.2 Record Layer: Application Data Protocol: http-over-tls
Content Type: Application Data (23)
Version: TLS 1.2 (0x0303)
Length: 101
Encrypted Application Data: 1303136ee3f0e6daf0cb0e82d07fcca423c9cb2a26b29e332cdc604397f43c377df9805e…
[Application Data Protocol: http-over-tls]
Reference
https://hpbn.co/transport-layer-security-tls/ HTTPS 权威指南 https://tls.ulfheim.net/ https://datatracker.ietf.org/doc/html/rfc5246
❤️ 看完三件事
如果你觉得这篇内容对你挺有启发,我想邀请你帮我三个小忙:
点个【在看】,或者分享转发,让更多的人也能看到这篇内容 关注公众号【趣谈前端】,定期分享 工程化 / 可视化 / 低代码 / 优秀开源。
点个在看你最好看