协议-TLS协议-客户端TLS解密的实现原理

参考来源:
练习实践-TLS协议01-Wireshark对https数据的解密
练习实践-TLS协议01-客户端curl配合sslkey文件实现解密
极客时间:网络排查案例课-实战二:应用层真实案例揭秘篇-20丨TLS加解密:如何解密HTTPS流量?

客户端如何做 TLS 解密?

这里说的客户端,包括了 Chrome、Firefox 等浏览器,也包括 curl 这样的命令行工具。
我在上节课里提过,为了把 TLS 解密,我们需要完成几个前提条件。其实这些前提条件就
是下面这三件事

1.创建一个用来存放 key 信息的日志文件,然后在系统里配置一个环境变量SSLKEYLOGFILE,它的值就是这个文件的路径。
2.重启浏览器,启动抓包程序,然后访问 HTTPS 站点,此时 TLS 密钥信息将会导出到这个日志文件,而加密报文也会随着抓包,被保存到抓包文件中。
3.在 Wireshark 里,打开 Preferences 菜单,在 Protocol 列表里找到 TLS,然后把(Pre)-Master-Secret log filename 配置为那个文件的路径。

可以参考之前写过的实践记录:练习实践-TLS协议01-Wireshark对https数据的解密
最后实现的效果是可以直接通过wireshark查看解密后的https层的内容;

这背后的原理是什么呢?(正餐)

其实是这样的:浏览器在启动过程中会尝试读取 SSLKEYLOGFILE 这个环境变量。如果存在这个变量,而它指向的又是一个有效的文件,那么浏览器就会做最为关键的事情了:它去调用 TLS 库,让 TLS 库把访问 HTTPS 站点的过程中的 key 信息导出到
SSLKEYLOGFILE 文件中。我画了一张示意图供你参考:
在这里插入图片描述
整个过程倒是不难理解,不过你可能会好奇:为什么这个日志文件有这么强大的能力,能解密 TLS?然后又不免担心,如果这个文件“被坏人利用了”,该怎么办?
所以我们还需要近距离地认识一下 SSLKEYLOGFILE。

SSLKEYLOGFILE文件介绍

SSLKEYLOGFILE这个文件之所以能够解密 TLS,最关键的是,TLS 库把密钥交换阶段的核心信息 Master
secret 导出到了这个文件中。基于这个信息,Wireshark 就可以还原出当时的对称密钥,从而破解密文。
我们先来认识一下 SSLKEYLOGFILE 的格式。它是由很多条记录组成的,对于 TLS1.2 来
说,每一行是一条记录,每一条记录由 3 个部分组成,中间用空格分隔,也就是下面这
样:


……

这三个部分的具体含义是这样的。
Label:是对这条记录的描述,对于 TLS1.2 来说,这个值一般是 CLIENT_RANDOM。
另外,RSA 也是一个可能的值,但是前面说过,因为 RSA 算法在密钥交换方面不是前向加
密的,所以已经不推荐使用了。所以如果你在日志文件里看到 RSA,可能要小心一点,说
明你的 TLS 不是前向加密的,所以并不是很安全。

**ClientRandom:这个部分就是客户端生成的随机数,**随机数原始长度为 32 字节,但在
这里是用 16 进制表示的,每个字节用 16 进制表示就会成为 2 个字符,所以就变成了 64
个字符的字符串。我们在抓包文件里也能看到它,因为在密钥交换算法的设计中,
ClientRandom 就是要在网络上公开传输的。

Secret:这就是 Master secret,也就是通过它可以生成对称密钥。Master secret 固定
是 48 字节,也是十六进制表示的关系,成为 96 个字节的字符串。你应该明白了,这个
Master secret 就是最为关键的信息了,也正是黑客苦苦寻求的东西。它是万万不能在网络
上传输的,自然也不可能在抓包文件里看到它,只有 TLS 库才能导出它。

补充:TLS1.3 的格式会很不一样,具体细节你可以参考这里的链接
在这里插入图片描述

SSLKEYLOGFILE 日志文件格式我们了解了,接下来了解 Wireshark 是怎么跟它协同工作,解开密文的

Wireshark 是怎么解开密文的–示例

CLIENT_RANDOM 770c2c73ef1ab58dda9360a94587e5f8b0a80c0b1abf628ddd7b55a118ec18ec bea2c01c5b6f9c577e8ba251c8f262adf33c5aa31a238d464a9c56dbd1bf30cf55cbf14e6175102fa1db9b8a0183a721

在 TLS1.2 的 SSLKEYLOGFILE 中,每条记录的第一列是 CLIENT_RANDOM 这个字符
串,第二列是这个 client random 的值,Wireshark 就是通过它,找到对应的 TLS 会话
(你可以理解为是 TCP 流)。就像上图所示,通过这个随机数,就找到了这条 KEYLOG
记录对应的 TLS 会话了。
在这里插入图片描述
在这里插入图片描述

那么接下来,Wireshark 就知道真正的 Master secret 在哪里了:它就是前面匹配了这个
客户端随机数的记录的第三列,也就是那 96 个字节的字符串。
在这里插入图片描述

由于在抓包文件里就有 ECDHE 密钥交换算法所需要的各种参数,结合这里的 Master
secret,Wireshark 就可以解析出对称密钥,从而把密文解密了!
在这里插入图片描述

SYSKEYLOGFILE 的安全性

现在回答一下前面的问题:如果这个文件“被坏人利用了”,怎么办?
通过前面的学习,我们知道了:要想破解密文,既要有抓包文件,也要有 SSLKEYLOGFILE
日志文件,两者结合才能解密。而且不要忘了,即使你有抓包文件和日志文件,要是没抓
到 TLS 握手阶段的报文,也还是不能解密,因为缺少了客户端随机数、加密算法参数等信
息,Master secret 对你也是无法下嘴的美食。

服务端如何做 TLS 解密?

其实,上面的客户端做解密的过程,网络上已经有很多资料了,但是接下来要介绍的“服
务端做 TLS 解密”这个话题,却鲜有人讨论。要知道,TLS 是双方的加密任务,但是我们
一边倒地关心客户端如何解密,却对服务端的解密不闻不问,这又是什么道理呢?

我觉得可能有这么几个原因:

多数人接触的还是以客户端为主,能在客户端解密已经满足了大多数的需求。而服务端
只有一部分专职运维或者开发工程师在维护,关注度少了很多。

服务端一般有详细的日志,比如 Nginx 可以向日志里输出 HTTP 头部和性能数据,还可以输出 TLS 选择的密码套件等信息,这些在一般场景下也够用了。

很多服务端程序并没有提供 TLS 解密的功能,也就是想做抓包解密也做不了。而要自己实现这个特性,难度跟简单的参数配置,不在一个等级。难度高,可能是更加关键的原因。

其实,在软件架构上,服务端和客户端也是类似的,也是基于 TLS 库来构建 TLS 加解密的能力的。
在这里插入图片描述
就我们 eBay 的情况来说,在我们的软件负载均衡方案中,第七层的部分是基于Envoy实现的。我们在把一套新系统搬上生产环境之前有一系列的考量,就像体检的检查表一样逐一校验。我们发现 Envoy 的体检就有一项“不合格”:Envoy 不提供对 TLS 流量进行抓
包解密的功能。

补充:Envoy 是硅谷的共享出行公司 Lyft 于 2016 年发起的开源项目,可以认为是云原生时代的 Nginx

在不少情况下,这个抓包解密特性对排查很有用。像一些商业产品比如 Netscaler 就是可以一边抓包,一边导出 TLS key。就跟我们在客户端做解密类似,我们结合这两个文件,就可以在 Wireshark 中既观察到 TCP 行为,也读到应用层信息了。
你可能会问:“Envoy 可以输出 Web 日志呀,把各种 HTTP 性能指标、访问头部,甚至包括用了什么 Cipher,都输出到文件,这样还不香吗?”

网络排查的两大鸿沟

其实,我在开篇词和第 4 讲中都提到过网络排查的两大鸿沟。

应用现象跟网络现象之间的鸿沟:你可能看得懂应用层的日志,但是不知道网络上具体发生了什么。
工具提示跟协议理解之间的鸿沟:你看得懂 Wireshark、tcpdump 这类工具的输出信息的含义,但就是无法真正地把它们跟你对协议的理解对应起来。

而包括 Envoy 在内的反向代理和 LB 软件,虽然也都提供了应用层日志,但跟实际的网络行为还有距离,这就是“应用现象跟网络现象之间的鸿沟”:日志是日志,网络是网络。
如果日志里说某个 HTTP 请求耗时很长,你是无法知道网络上到底什么问题导致了这么长的耗时,是丢包引起了重传?还是没有丢包,纯粹是传输速度慢呢?
为了跨越第一个鸿沟,我们选择做 tcpdump 抓包。但是,如果抓取到的 TLS 密文无法被解密,就无法知道这些究竟是应用层的什么信息,这个鸿沟依然没有被跨越。
在这里插入图片描述
当然,我们可以选择“妥协”,采用一些灵活的策略来开展抓包分析。比如,可以把抓包分析的重心转移到 TCP 和 TLS 本身的层面,而不再关心其承载的应用层信息。但是“隔靴搔痒”总让排查工作不是特别“痛快”,我们犹豫许久之后,还是决定把这个解密的特性实现!

这并不是一件容易的事情。不过通过调研,我们发现,其实在服务端启用跟客户端类似的TLS 解密功能,技术上是可行的,其中最为关键的信息就在 2017 年一位 Wireshark 开发工程师的演讲中:
Applications using OpenSSL 1.1.1 or BoringSSL d28f59c27bac (2015-11-19) can
be configured to dump keys: void SSLCTXsetkeylogcallback(SSL CTX ∗ctx, void
(∗cb)(const SSL ∗ssl, const char ∗line));

也就是说,只要我们使用这个 BoringSSL(是谷歌 Fork 自 OpenSSL 的项目)的
SSLCTXsetkeylogcallback() 回调函数,就可以把 TLS 信息导出来,于是我们信心大
增。核心突破就是要把这个 BoringSSL 的回调函数给用起来。

具体来说,我们需要做这样的几件事:
在 Envoy 代码中增加调用 SSLCTXsetkeylogcallback() 函数的逻辑。
增加了对外的接口,使得用户可以通过某种方式让 Envoy 知道,它需要去使用这个调用逻辑

第二点,其实就是一种接口方式,比如 SSLKEYLOGFILE 环境变量就是一种,我们也可以选择 API 接口,或者某种别的接口。总之,只要让程序(这里是 Envoy)知道:它需要去叫 BoringSSL 这个小弟去办点事情,整个功能就可以运作起来了。你可以参考这张示意图:

在这里插入图片描述
这个特性的主要开发者张博已经提交了 PR,相信不久之后我们就能在正式版的 Envoy里用上这个特性了。

实现 Envoy 的 TLS 抓包解密的具体的做法跟客户端解密的步骤差不多:

1.调用 Envoy 接口,启用 SSL KEY 导出功能。
2.做 tcpdump 抓包,然后把抓包文件和 KEY 文件复制出来。
3.在 Wireshark 里同样配置好 TLS 协议的 (Pre)-Master-Secret log filename,打开抓包文件后,就可以跟在客户端类似,直接看到明文了。

几个问题

然后到这里,这里我们还需要搞清楚几个问题。

问题 1:我想实时查看解密信息行不行?

一个字的答案:行。只要设置好前面提及的 3 件事:

SSLKEYLOGFILE 环境变量;
之后再启动浏览器,然后直接在 Wireshark 里开始抓包;
设置 Wireshark 的 TLS 协议,配置 (Pre-)Master secret logfile。

这时候你访问 HTTPS 站点时,在 Wireshark 里看到的就直接是解密好的信息了!因为Wireshark 已经能从 SSLKEYLOGFILE 里读取到密钥信息,同时又在实时地抓取到 TLS 密文,这种解密工作是可以实时进行的。
当然,这里还有一个小的注意点,我们在第二个问题里展开。

问题 2:为什么停止抓包后再启动抓包,抓包文件又变成密文了?

有同学就遇到这个问题:重启浏览器后,在 Wireshark 里马上就能看到 HTTP 数据包,确实能解密。但是停止抓包之后,再启动抓包,看到的又变成了 TLS 密文了。必须得重启浏览器才行。这是为何呢?

表面上看,这似乎又是一个“重启大法”的问题,但本质上呢?

我们知道,密文是用对称密钥加密的。而对称密钥的生成,是在 TLS 握手阶段完成的。我们前面提到过,Wireshark(也包括其他需要读取 SSLKEYLOGFILE 的程序)正是根据第二列的客户端随机数,来找到抓包文件中的 TLS session,然后运用第三列的 Master secret
来获取到对称密钥的。

抓包停止后,新的 HTTPS 请求所触发的 TLS 握手就不会被抓取到。这也就意味着,Wireshark 没有抓取到客户端随机数这个关键信息,尽管 SSLKEYLOGFILE 里依然在输出着一行行的 key 信息,但是 Wireshark 已经不知道用哪个 Master secret 了。自然,解密
就无从做起。
在这里插入图片描述
而在浏览器重启后,事实上造成了 TLS 的重新握手,此时就又可以抓取到客户端随机数了,这样,解密工作就可以恢复。你看,这其实跟第 3 讲中,没抓到 TCP 握手报文就无法知道 Window Scale 参数这个问题差不多,也是关于握手的,只不过这次是 TLS 握手。“技术是相通的”,这句话真不是随便说说。

小结:
如何做到对抓包文件进行解密。这里又分客户端和服务端两个不同场景,你也需要重点关注。
首先,在客户端做抓包解密,需要做三件事

创建一个文件,并设置为 SSLKEYLOGFILE 这个环境变量的值;

重启浏览器,开始做抓包,此时 key 信息被浏览器自动导入到日志文件;

在 Wireshark 里把该日志文件配置为 TLS 的 (Pre)-Mater-Secret log filename。

这样,我们就能在 Wireshark 里直接读取到应用层信息了。
而在服务端抓包解密,就要依托于软件实现了,但是有些软件并没有提供这种功能,比如Envoy。借助底层 BoringSSL 库的接口,eBay 流量管理团队实现了对这个接口的调用,我们也可以在 Envoy 上完成抓包解密了。

另外,你还要知道 Wireshark 能解读出密文的原理

从抓包文件中定位到 client random;
从日志文件中找到同样这个 client random,然后找到紧跟着的 Master secret;
用这个 Master secret 导出对称密钥,最后把密文解密。

思考题:

DH、DHE、ECDHE,这三者的联系和区别是什么呢?

浏览器会根据 SSLKEYLOGFILE 这个环境变量,把 key 信息导出到相应的文件,那么
curl 也会读取这个变量并导出 key 信息吗?

作者回复: 服务端要看具体情况。如果服务端使用的SSL库也是openssl lib,那理论上也可以导出key log。以nginx为例,大体步骤如下:

1.下载https://git.lekensteyn.nl/peter/wireshark-notes/tree/src/sslkeylog.c,然后gcc
2. 检查自己的nginx使用的ssl库:ldd /usr/sbin/nginx |grep ssl
3. 安装libssl-dev
4. 编译第一步下载的c源代码cc sslkeylog.c -shared -o libsslkeylog.so -fPIC -ldl
5. 查看nginx进程使用的动态链接库 lsof -n -p $(pidof nginx | awk ‘{print $1}’) | grep ssl
类似这样的输出

# lsof -n -p 10313 |grep ssl
nginx   10313 root  mem    REG              254,1   442984   3255 /usr/lib/x86_64-linux-gnu/libssl.so.1.1
nginx   10313 root  mem    REG              254,1    14224  20914 /usr/local/lib/libsslkeylog.so
  1. 新建环境变量SSLKEYLOGFILE=~/sslkey.log
  2. 配置nginx使用TLS证书,然后访问一次nginx上的https站点,就有key输出了

问题回复参考

问题一:
1 DH算法是为了解决密钥协商的算法,Bob和Alice分别用对方的公钥和自己的私钥,一通骚操作后,得到相同的会话密钥k,这就解决了密钥不直接传输而通过协商出来;
2 DH有static DH和DHE两种实现,static的方式,私钥是不变的,有被破解的可能性,进而搞出来DHE,每次双方的私钥都变化,安全性提高了不少;
3 DHE算法性能不行,然后出现基于椭圆曲线的ECDHE;
参考:https://www.likecs.com/default/index/show?id=124371

问题二:
经过测试curl也会读取SSLKEYLOGFILE,并把随机数和secret写入到这个文件中
SSLKEYLOGFILE=/my/path/to/file.log curl https://example.com
参考:https://davidhamann.de/2019/08/06/sniffing-ssl-traffic-with-curl-wireshark/

这个报错是因为在你的代码中使用了一个隐式声明的函数`SSL_CTX_set_keylog_callback`,而编译器找不到该函数的声明。这通常是因为你没有包含相应的头文件或者链接到正确的库文件。 根据你提供的引用内容,问题可能是由于openssl版本的问题导致的。你可以尝试更新openssl库或者查看你的配置文件是否正确配置了openssl的路径。 另外,你可能还需要检查一下你的代码中是否正确包含了所需要的头文件。如果需要使用`SSL_CTX_set_keylog_callback`函数,你需要包含对应的头文件。 总结起来,解决这个问题的步骤如下: 1. 确认你的代码正确包含了所需要的头文件,特别是与SSL相关的头文件。 2. 检查你的配置文件是否正确配置了openssl的路径。 3. 更新openssl库,确保你使用的是最新的版本。 希望这些信息对你有帮助!<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [关于linux python3.7版本 No module named ‘_ssl‘报错](https://blog.csdn.net/tigerqax/article/details/108241808)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [SSL解密](https://blog.csdn.net/weixin_33957648/article/details/94650032)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值