19

20190402112314.png

此前一篇文章用 wireshark 这个抓包工具调试了一下 HTTP 请求和响应。详细阐述了 TCP 连接和断开的整个过程。这篇文章尝试使用 wireshark 来抓取 TLS 封包,了解一下 HTTPS 请求和响应的整个过程。 🌞

懒得看全文的直接拉到最下看 TLS 流程的图片解释

首先准备好 curl 和 wireshark,这些谷歌一下怎么安装。 😝

HTTPS 是基于 TLS 之上的,如果没有目标的私钥是没办法解密的,如果直接使用 wireshark 是看不到 TLS 层加密的信息的。

打开 wireshark 并开启抓包,在 curl 中发送一个请求:

20190401103640.png

再 wireshark 输入 tls 过滤请求,疑似 ip 地址为目标网站

20190401103736.png

输入该 ip 地址,确认是目标网站 httpbin,然后尝试查看返回的数据信息,因为 TLS 加密是看不到返回的 JSON 数据的

20190401103921.png

因 TLS 使用的是迪菲 - 赫尔曼密钥交换生成对称密钥的加密算法,因此需要获取到一系列生成密钥的必要信息后才可生成密钥解密数据。

先不着急怎么解决这个问题,首先回顾一下几个知识点,大概了解一下加密算法和 CA 数字证书和 TLS 加密流程:

必要的几个知识点 📖

加密算法 🔒

远古以前用的是对称加密,这种加密和解密的密钥是同一个,因此极为不安全,一旦其中一个密钥泄露,那么就会导致加密文件被破解

后来发明了非对称加密,这种加密方式的逻辑就是公钥用来加密,私钥用来解密,一方使用另一方的公钥进行加密,传输密文给另一方,另一方再用私钥进行解密,这样没有拿到私钥就无法解密密文。但这种加密解密效率较低,后来就衍生出了混合加密,这种加密方式综合了非对称加密和对称加密。

混合加密首先使用非对称加密生成对称密钥,然后再使用对称密钥进行数据安全传输,这样加密解密的效率要高得多了。TLS 用到的迪菲 - 赫尔曼就是其中的一种

关于迪菲 - 赫尔曼密钥交换算法,这里简单提一下,这种算法有几个特点:

  1. 密钥可以合成但不能分解
  2. 合成后的密钥可以继续再合成
  3. 合成后的密钥结果与合成顺序无关
  4. 本质上是一种生成密钥算法

这个算法的加密流程是这样的:

  • A 和 B 想要交换并生成对称密钥
  • A 将 P 发送给 B
  • A 使用 P 和自己的私钥 SA 合成 PSA
  • B 使用 P 和自己的私钥 SB 合成 PSB
  • 双方交换 PSA 和 PSB
  • A 使用私钥 SA 与 PSB 合成 PSBSA
  • B 使用私钥 SB 与 PSA 合成 PSASB

这样对称密钥 PSASB 和 PSBSA 就合成完毕了,双方就可以使用这个对称密钥对传输的数据进行加密 🔑

⚠️ 问题是 A 将 P 发送给 B,B 如何确认 P 就是真的来自 A 的呢,而不是受到中间人攻击篡改了 P,这就需要使用 CA 认证了,只要有 CA 认证后的数字签名并且通过 CA 的公钥能够验证那么就可以确认 P 就是来自 A 的。

数字证书 📄

因此这里提一下 CA 证书也简单提一下原理:

一个网站 A 想要获取数字证书,那么要走如下流程:

  • A 将网站信息和公钥 PA 发送给 CA 认证机构
  • CA 认证机构验证网站信息并用自己的私钥 SCA 加密生成数字签名,并回传给 A
  • A 收到的数字签名中就包含了 A 的公钥 PA,那么其他人只需要通过 CA 认证机构的公钥即可认证解密数字签名,获取数字签名中的公钥 PA 了
  • 那么其他人就可以确定 PA 确实是来自 A 的

这样 A 的公钥 PA 就可以被认为确实是来自 A 的,因为有 CA 签发的数字证书认证和背书。 🥂

⚠️ 还有一个问题是 CA 的公钥谁来认证呢?要是 CA 的公钥也被恶意替换了怎么办?那么就需要 CA 的 CA 来认证了,那么 CA 的 CA 的公钥谁来认证?根据这个逻辑,最后有一个 root CA,这个 CA 用来做最后的权威鉴定。

TLS 加密流程 👷

最后来回顾一下 TLS 的加密流程

TLS 是建立在 TCP 基础上的,因此必定需要先三次 TCP 握手建立 TCP 连接,然后再是建立 TLS

  1. Client Hello

    1. Client Hello 报文:客户端对加密算法的支持度不同,因此需要向服务端发送客户端支持的 加密套件(Cipher Suite) ,同时还要生成一个 随机数 同时保存在客户端和发送给服务
  2. Server Hello

    1. ServerCertificate 报文:服务端收到 Client Hello 之后,向客户端发送 CA 认证的数字证书,用来鉴别服务端身份信息,同时还要生成一个 随机数 同时保存在服务端和发送给客户端
    2. Server Hello Done 报文:表示服务端宣告第一阶段的客户端服务端握手协商结束
    3. 可选:Certificate Request 报文:必要情况下,要求客户端发送证书验证身份
    4. 可选:Server Key Exchange 报文:如果 CA 认证的数字证书提供的信息不够,服务端还可发送提供补充信息
  3. Client Finish

    1. Client Key Exchange 报文:客户端收到 CA 数字证书并通过验证,然后通过 CA 公钥解密获取到 服务端公钥。Client Key Exchange 报文包括有一个随机数,这个随机数被称为 Pre-master key/secret;一个表示随后的信息使用双方协商好的加密方法和密钥发送的 通知 ;还有一个通过协商好的 HASH 算法对前面所有信息内容的 HASH 计算值,用来提供服务端校验。这些信息都通过服务端公钥加密传送给服务端
    2. ClientCipherSpec 报文:该报文通知服务端,此后的通信都将使用协商好的加密算法计算对称密钥进行加密通信(也就是使用两个随机数以及第三个 Pre-master key/secret 随机数一起算出一个对称密钥 session key/secret
    3. Finished 报文:该报文包括连接至此的所有报文的校验值,使用服务端公钥进行加密
    4. 可选:ClientCertificate 报文:如果服务端请求,客户端需要发送 CA 数字证书
    5. 可选:CertificateVerify 报文:服务端如果要求 CA 数字证书,那么需要通过 HASH 算法计算一个服务端发送来的信息摘要
  4. Server Finish

    1. 服务端最后对客户端发送过来的 Finished 报文使用服务端私钥进行解密校验
    2. ClientCipherSpec 报文:报文通知服务端,此后的通信都将使用协商好的加密算法计算对称密钥 session key/secret 进行加密通信
    3. Finished 报文:标志 TLS 连接建立成功
  5. TLS 握手成功此后通过对称密钥 session key/secret 加密通信
以上,我们看到生成的两个随机数和 Pre-master key 一起计算生成 session key 就是通过上文中提到过的迪菲 - 赫尔曼密钥交换算法实现的。客户端收到 CA 数字证书获取到服务端公钥进行加密,也符合上文中提到的 CA 认证流程。服务端私钥解密客户端使用服务端公钥加密,在上文中的非对称密钥部分也进行了讲解。因此 TLS 是一个运用到多种认证、加密的安全传输技术。除此之外,上文中没有提到的使用 HASH 计算的目的则是为了防止数据遭到篡改,这跟我们大家在网上下载软件,计算 md5 校验是一个原理。

⚠️ 如有不正确的地方,各位请在评论区指正谢谢

最后抓包验证上述加密流程 📦

首先上文提到过 wireshark 直接抓取 TLS 的封包是没办法看到解密后的数据的,那么我们需要通过一些手段获取到解密后的数据

那么如何才能解密获取数据呢,这里有篇文章可以看看 https://jimshaver.net/2015/02...

It turns out that Firefox and Chrome both support logging the symmetric session key used to encrypt TLS traffic to a file. You can then point Wireshark at said file and presto! decrypted TLS traffic.

原理是浏览器会在系统中存在名为 SSLKEYLOGFILE 的环境变量已经设置的情况下,将每个 HTTPS 连接产生的客户端或服务端的随机数、preMasterSecret、MasterSecret 全部获取到并保存在这个环境变量指定的文件中。

配置环境变量 🎀

开始动手实操,这里用的是 windows 系统,我们配置环境变量:

20190402102813.png

配置完成,这样浏览器就会写入密钥信息到指定路径的文件中

至于 macOS/Linux 自己谷歌一下如何设置环境变量,很简单不再赘述

配置 wireshark 🦈

打开 wireshark,点击配置信息指定 TLS 的 Pre-master key 路径为环境变量指定的那个文件路径

20190402103310.png

这样配置就算完成了,我们尝试一下打开 chrome 浏览器访问一个 https 网址:

20190402103505.png

这里访问了百度的首页,可以看到 wireshark 展现的已经是解密后的数据了

开始抓包分析 TLS 握手流程 🤝

然后打开终端使用 curl 发送一个 https 请求

20190402103644.png

还是以 httpbin 为例,过滤 http 查看 wireshark 的结果:

20190402103810.png

右键 follow 一下

20190402104000.png

这就是整个 TCP 建立到 TLS 握手再到 HTTP 请求响应以及 TCP 断开的整个过程,我们逐一分析一下:

TCP 的此前文章已经说过了,这里也不再提了,直接看 TLS 部分:

Client Hello

20190402104310.png

Client Hello 阶段,客户端给服务端发送一个随机数,以及 Cipher Suites 客户端支持的所有加密套件

Server Hello

20190402104516.png

Server Hello 阶段,服务端给客户端发送一个随机数,以及选中的 Cipher Suite 加密套件

然后服务端继续发送给客户端 CA 数字证书以及 Server Key Exchange 和 Hello done 信息完成第一阶段的握手:

20190402104857.png

这个是证书:

20190402104929.png

这个是 Server Key Exchange,可以看到协商了一种加密算法:

20190402105005.png

这个是 Server Hello Done:

20190402105206.png

Client Finish

20190402105705.png

客户端发送一个 Client Key Exchange,Change Cipher Spec 和 Finished 报文

Finished Verify Data 包括至此连接的所有报文的校验信息,用服务端提供的公钥加密

客户端准备好切换为对称密钥加密

Server Finish

20190402110401.png

最后服务端返回一个 Change Cipher Spec 和 Server Finish

服务端准备好切换为对称密钥加密

TLS 握手成功

至此,TLS 握手成功,在 wireshark 中就可以看到接下来就是 HTTP 的请求响应封包了:

20190402110657.png

图片解释 🖼

最后画了个简化版的脑图方便理解:

20190402111708.png

⚠️ 如有不正确的地方,各位请在评论区指正谢谢

JS 菌公众账号

请关注我的订阅号,不定期推送有关 JS 的技术文章,只谈技术不谈八卦 😊


JS菌
6.4k 声望2k 粉丝