HTTPS 原理解析
HTTP 协议是明文传输,它简单易于理解,但同时也带来了安全性问题,在复杂的网络环境中,HTTP 流量几乎是在裸奔,可以轻易被监听,为了解决这个问题,人们提出了 HTTP over SSL 即 HTTPS,即通过 ssl 隧道来传输 HTTP 流量,这样加密了 HTTP 数据包,实现了传输链路上的安全性。相比于 HTTP,HTTPS 在 TCP 层上多了一个 SSL/TLS 层。
HTTPS 的通信过程
SSL/TLS
SSL(Secure Socket Layer,安全套接字层):1994 年为 Netscape 所研发,SSL 协议位于 TCP/IP 协议与各种应用层协议之间,为数据通讯提供安全支持。
TLS(Transport Layer Security,传输层安全):其前身是 SSL,它最初的几个版本(SSL 1.0、SSL 2.0、SSL 3.0)由网景公司开发,1999 年从 3.1 开始被 IETF 标准化并改名,发展至今已经有 TLS 1.0、TLS 1.1、TLS 1.2 三个版本。SSL3.0 和 TLS1.0 由于存在安全漏洞,已经很少被使用到。TLS 1.3 改动会比较大,目前还在草案阶段,目前使用最广泛的是 TLS 1.1、TLS 1.2。
可以简单认为 SSL 与 TLS 是描述的同一种协议,本文中不做区分,SSL/TLS 是为了在 TCP 连接上添加一个加密隧道来加密通信流量,可以确保通信流量安全无法解密。
图解
由于 HTTPS 的 TLS 层是在 TCP 上的,所以与 HTTP 一样,在建立 TLS 连接之前必须先 TCP 三次握手
HTTPS 的通信过程可以由下图简单表示。
步骤详解
0x01 ClientHello
- ClientHello。 首先 https 请求是基于 http 的,也就是基于 tcp 的,所以先得建立 tcp 三次握手,这个就不说了,然后 tcp 握手后是 SSL 层的握手,也就是图中的 ClientHello 消息,client 发送本地最新的 TLS 版本、算法组合的一个集合和其他很多辅助的信息,并且生成一个随机数 A。
ClientHello.png
可以看到随机数(
1 | Random |
)是一个 GMT UNIX 时间加上一串随机字节,算法组合(
1 | Cipher Suite |
)有 26 种。还有 ClientHello 并不是我随便叫叫的,真的叫 ClientHello😢……
- ServerHello。Server 收到这些信息后比对自己的 TLS 版本,选择其中低的一个作为返回,并且从算法组合的集合中选出一种合适的组合,然后同样也生成一个随机数 B,一起打包到 ServerHello 中传回给 Client。内容如图(
ServerHello.png
):
ServerHello.png
同样 ServerHello 也不是随便叫的,可以看到随机数格式和 ClientHello 一样,并且这里选出了一种 CipherSuite 算法组合。
- Certificatie,ServerHelloDone。服务端在选出沟通策略之后将自己的证书信息告诉 Client 端(
Certificate
),通知 Client 关于秘钥更新的信息(ServerkeyExchange
),接下去就看你的了,并且表示该发的都发给你了,我的 Hello 结束了(ServerHelloDone
)。
Certificate-ServerHelloDone.png
Client 收到 2,3 步的信息后先验证证书是不是合法的,包括它的颁发机构,域名匹配,有限期限等,这个具体的过程就不探究了,只要知道这些步骤就行了。
证书验证通过之后,生成随机数 C1, 然后用证书内容中的公钥通过服务器选择的非对称加密算法加密,得出为 C2。
由之前的三个随机数 A、B、C1 通过一个伪随机函数再生成一个 D, 注意!这个是最终 http 真正使用的加密秘钥!!!。
由 D 再次通过伪随机函数生成一个秘钥组,包含 6 个秘钥,假设为 P1,P2,P3,P4,P5,P6。
ClientKeyExchange。通知 Server 秘钥相关的信息,发送第 5 步中算出的 C2 给 Server 端。
Client 端发送 ClientKeyExchange 之后,计算之前所有与 Server 端交互消息的 hash 值,假设为 client_hash1,用步骤 7 中得到的其中一个 P1 进行加密,结果为 E。
Server 端收到 C2 后用私钥结合非对称算法解密 C2,得到 C1。
同样的 Server 端也根据 A、B、C1 由伪随机函数生成 D ( 最终的加密秘钥!!!), 再由 D 得出秘组钥(P1-P6),因为这里涉及到的算法都是一样的,所以得出的秘钥也是一样的。
Server 端计算之前所有和 Client 端交互消息的 hash 值,假设为 server_hash2,大家可能发现了,11、12 跟 Client 端的 6、7、9 过程一致,只是少了 9 中的 P1 加密过程。
这个时候 Client 端会发送 ChangeCipherSpec 消息和 EncryptedHandshakeMessage 消息,通知 Server 端接下去使用选定的加密策略来通信了,并且将第 9 步中的 E 传给了 Server。(这里几个步骤的顺序只是为了好理解一点而这样排列,实际两条线是独立在处理信息的,所以先后顺序不能保证)
这个时候 Client 会再次计算之前握手消息的 hash 值,得出结果 client_hash2。
Server 在收到 EncryptedHandshakeMessage 消息带过来的 E 之后,利用步骤 11 中的 P1 解密 E,由于加密算法和 P1 都是相同的,所以这里还原出了 client_hash1,然后与步骤 12 中的 server_hash2 比对,如果一样说明之前的几条协商秘钥的消息都被对方正确无误的理解了。
Server 端再次对之前的消息做 hash 值,得出 server_hash2,用 P2 进行加密结果为 F,然后通过 ChangeCipherSpec-EncryptedHandshakeMessage 消息传给 Client 端。
Client 收到 Server 的消息后根据 P2 解密 F 还原得出 server_hash2,与 client_hash2 比对如果一致,则认为之前的交互过程都是正确无误且被对方理解的。至此,整个握手过程就结束了,之后的 http 数据报就会被之前确定的加密策略和加密秘钥 D 进行加密传输了。