熟悉而陌生的老朋友--HTTPS协议

无论你是前端、后端或者是爬虫工程师,相信你一定会和 HTTPS 协议打交道。它更像是一位熟悉而陌生的老朋友,我们可能只知道它能够保证数据传输的安全性,但是对实际原理模糊不清。今天我们就利用 Wireshark 抓包工具好好撸一下 HTTPS 协议,搞清楚他的交互过程。

HTTPS 简介

HTTPS (Hypertext Transfer Protocol Secure) 是基于 HTTP 的扩展,用于计算机网络的安全通信,已经在互联网得到广泛应用。在 HTTPS 中,原有的 HTTP 协议会得到 TLS (安全传输层协议) 或其前辈 SSL (安全套接层) 的加密。因此 HTTPS 也常指 HTTP over TLS 或 HTTP over SSL。

TLS/SSL 握手流程

TLS/SSL 中最重要的就是握手过程,可以简要概括为以下四步:

1.Client 和 Server 交换 Hello 信息,信息中包含了随机数、确定了后续交互使用的加密算法

2.双方单向/双向发送证书,允许 Client 和 Server 进行身份认证

3.根据之前选择的密钥协商算法(RSA、(EC)DHE 等),协商出预备主密钥

4.Client 和 Server 通过预备主密钥、随机数计算出主密钥,用于后续数据加密传输

Wireshark 抓包

Client Hello(Client -> Server)

主要作用是告诉 Server,Client 所支持的 TLS 协议版本、支持的加密算法等等。

Client 随机数(Random):Client 生成的随机数,暂时称作 ClientHello random,用于后续的主密钥生成。

会话 ID(Session ID):当 Client 通过一次完整的握手,与 Server 建立了一次完整的 Session,Server 会记录这次 Session 的信息,以备恢复会话的时候使用。上图中该字段为空,说明这是第一次连接到服务器。

加密算法套件(Cipher Suite):包含了 Client 所支持的密码算法套件。TLS 中使用的密码套件有一种标准格式。上面的抓包中,Client 发送了 46 套加密套件,Server 会从中选出一种用于本次加密连接使用。一个加密算法套件是 4 个算法的组合。

压缩方法(Compression Methods):加密之前的压缩算法。这个字段在 TLS 1.2 中用的不多。在 TLS 1.3 中这个字段被删除。

扩展(Extension):结构定义是一个枚举类型,用于携带一些扩展参数,加强 TLS 功能。(携带域名,是否支持 http/2.0 等等)

Server Hello(Server -> Client)

收到 Client Hello 之后服务器必须发送 Server Hello 信息,Server 会检查 TLS 版本和算法的 Client Hello 的条件,如果服务器接受并支持所有条件,它将发送其证书以及其他详细信息。否则,服务器将发送握手失败消息。

Server 随机数(Random):Server 生成的随机数,暂时称作 ServerHello random。注意,至此 Client 和 Server 都拥有了两个随机数。

会话 ID(Session ID):服务器将约定的 Session 参数存储在 TLS 缓存中,并生成与其对应的 Session id。它与 Server Hello 一起发送到 Client。Client 可以写入约定的参数到此 Session id,并给定到期时间。Client 将在 Client Hello 中包含此 id。如果 Client 在此到期时间之前再次连接到服务器,则服务器可以检查与 Session id 对应的缓存参数,并重用它们而无需完全握手。这非常有用,因为服务器和 Client 都可以节省大量的计算成本。

加密算法套件(Cipher Suite):抓包中 Server 选择了 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f),其中密钥协商算法是 ECDHE、身份认证算法是 RSA、加密模式是 AES_128_GCM、消息认证码算法(MAC)是 SHA256。

压缩方法(Compression Methods):如果支持,服务器将同意 Client 的首选压缩方法。

扩展(Extension):同上,只有由 Client 给出的扩展才能出现在 Server 的列表中。

Certificate(Server -> Client)

Server 将数字证书和到根 CA 整个链发给 Client,使得 Client 能用证书中公钥进行认证。

Server Key Exchange(Server -> Client)

主要作用是根据不同的密钥协商算法交换必要的密码信息。

如果密钥协商算法是 (EC)DHE,所以需要此阶段传递 DH 参数和 DH 公钥。

如果密钥协商算法为 RSA ,Client 不需要额外参数就可以计算出预备主密钥,然后使用 Server Certificate 中的公钥加密发送给 Server,所以不需要此阶段。

Certificate Request(Server -> Client, 可选)

这一步是可选的,如果有则表示双向认证。如果在对安全性要求高的常见可能用到。服务器用来验证 Client。服务器端发出 Certificate Request 消息,要求 Client 发他自己的证书过来进行验证。例如银行给你发的 USB 盾牌。

Server Hello Done(Server -> Client)

此消息完成握手协商的服务器部分,它不携带任何附加信息。

从 Server Hello 到 Server Hello Done,有些 Server 的实现是每条单独发送,有 Server 实现是合并到一起发送。Sever Hello 和 Server Hello Done 都是只有头没有内容的数据。

Certificate(Client -> Server, 可选)

如果 Server 要求发送 Client 证书,Client 便会在该阶段将自己的证书发送过去。Server 在之前发送的 Certificate Request 消息中包含了服务器端所支持的证书类型和 CA 列表,因此 Client 会在自己的证书中选择满足这两个条件的第一个证书发送过去。若 Client 没有证书,则发送一个 no_certificate 警告。

Client Key Exchange(Client -> Server)

主要作用是交换或者协商出预备主密钥,用于主密钥的计算。

对于 RSA 握手协商算法来说,Client 会生成的一个 48 字节的预备主密钥,其中前 2 个字节是 ProtocolVersion,后 46 字节是随机数,用 Server 的公钥加密之后通过此阶段发给 Server,Server 用私钥来解密。

对于 (EC)DHE 密钥协商算法来说,预备主密钥是双方通过椭圆曲线算法生成的,双方各自生成临时公私钥对,保留私钥,将公钥发给对方,然后就可以用自己的私钥以及对方的公钥通过椭圆曲线算法来生成预备主密钥。此时传递的是 (EC)DHE 算法公钥(图中的 Pubkey),预备主密钥是密钥在双方不直接传递密钥的情况下得到的。

当 Server 获得了可以计算预备主密钥的所有条件后,结合之前的 ClientHello random 和 ServerHello random,通过伪随机函数 PRF 生成并截取 48 字节为主密钥,用于后续对称加密传输数据的密钥,Client 同理。

Change Cipher Spec(Client -> Server)

主要作用是表明接下来传输数据过程中可以对应用数据协议进行加密了。

密码切换协议,表示随后的信息都将用双方商定的加密方法和密钥发送(Change Cipher Spec 是一个独立的协议,体现在数据包中就是一个字节的数据,用于告知 Server,Client 已经切换到之前协商好的加密套件(Cipher Suite)的状态,准备使用之前协商好的加密套件加密数据并传输了。其中第一条加密的消息就是接下来的 Encrypted Handshake Message

Encrypted Handshake Message(Client -> Server, 也称 Finshed)

生成对称加密密钥之后,发送一条加密的数据,让 Server 解密验证,确认密钥的正确性。

Change Cipher Spec(Server -> Client)

密码切换协议,Server 和 Client 一样,告诉 Client 可以开始加密通信。

Encrypted Handshake Message(Server -> Client, 也称 Finshed)

生成对称加密密钥之后,发送一条加密的数据,让 Client 解密验证;如果对方可以解密,则双方认证无误开始通信。

APPLICATION_DATA(CLient <-> Server)

这个阶段就很简单了,数据开始加密传输。

说在最后

HTTPS(TLS/SSL)协议中涉及了部分密码学概念,相比于其他协议更加复杂,本文也只是描述了大致握手流程。在当前主流 HTTP 框架中大多都对 TLS/SSL 相关逻辑做了很好的兼容,在访问 HTTPS 请求中,HTTP 框架已经为我们做好了所有握手流程,因此不了解此协议也是无可厚非。

其实不少的同人检测算法中已经涉及了 TLS/SSL 协议,例如JA3 算法,JA3 算法收集了 SSL 请求里面的信息,包括但不限于 TLS/SSL 版本,Cipher Suites数量,浏览器扩展列表,elliptic curves等等,所以你无论是更换 IP、User-Agent 等等都会被识别。当然,如果你了解TLS/SSL协议,修改HTTP框架的SSL的握手参数,此算法就可以迎刃而解了。