继续 TLS(或 SSL, HTTPS) 的话题。在我们诊断 HTTP 请求时,为了验证代码中发送了什么样的请求,会用 curl 或 Postman 的辅助,但它们都可能会带上额外的请求头等信息,最为可靠的办法是用网络抓包工具如 Wireshark, 从中看到的 HTTP 文本协议内容才是真正往外发送的内容。可是对于 HTTPS 的协议数据用 Wireshark 抓取到了也没用,因为它是加密了的,作为 TLS 的 Payload, 如果不知道加密算法或密钥是解不开来的。客户端与服务端的密钥交换是采用非对称方式加密的,只通过抓网络包是不可能知道最终确定的密钥是什么,除非像 Zscaler 那样堂而皇之地作为中间人攻击(man in the middle attack)。
但既然是本地浏览器能理解的网页内容,只要浏览器留了口子的话,也是有办法在 WireShark 中显示出抓取到的 HTTPS 的内容,那就是设置环境变量 SSLKEYLOGFILE, 然后启动浏览器(FireFox 或 Chrome), 就会把通信过程中的密钥记录到文件中,WireShark 中引用该 SSLKEY 文件就能显示出确切的 HTTP 请求的内容。
为了加强理解 TLS 与 HTTP 的关系,我们回顾一下网络的协议层,通常我们会采用两种分层模型:OSI(Open System Interconnect: 开放系统互联) 七层模型 与 DoD(Department of Defense: 美国国防部) 四层模型。从下图我们将看到 TLS 和 HTTP 分属哪一层
从上图中看到 TLS 在七层模型中是处于表示层,HTTP 处理它的上层应用层,而在四层模型中传输控制层之上的都是应用层,所以 TLS 是处于应用层,而 HTTP 只是作为它的 Payload 而存在。从而确切的讲并不存 HTTPS 这样一种协议,而是 TLS 之上的 HTTP(HTTP over TLS)。也就为什么正常情况下抓取到的网络包只看到 TLS 层,而其中的整个 HTTP 协议数据都是加密的,包括 URL, 请求头与请求求体。
仍以上一篇 自签发证书配置 HTTPS 单向双向验证 中配置的 Nginx 为例,如果正常在浏览器中访问 https://server.local, 则在 Wireshark 中看到的内容是
看不到 HTTP 的请求内容,它是加密了的,作为 TLS 协议的 Encrypted Application Data。
这里也可以解除某些人对 HTTPS 的安全担忧,只要启用了 HTTPS,整个 HTTP 协议数据都是加密的,不光对请求/响应体加密传输,对请求/响应用头,以及地址栏中看到的完整 URL(包括请求参数)都是加密传输的。此时真正要防患的是隔壁有没有一个老王(man in the middle), 所以又发展出更安全的 mTLS,可是又不能让所有网站给所有客户分配一个客户端证书。
下面的操作就是要让在本地浏览时,Wireshark 的 Application Data 展示为解密后的 HTTP 协议内容,步骤如下
设置环境变量 SSLKEYLOGFILE
依据不同的操作系统来配置该环境变量,如在 macOS 或 Linux 下的终端中
export SSLKEYLOGFILE=/tmp/sslkeys.log
应用环境变量 SSLKEYLOGFILE 启动浏览器
mac OS 或 Linux 下在同一个终端中,FireFox 和 Chrome 支持环境变量 SSLKEYLOGFILE。比如要启动 FireFox 浏览器,以 mac OS 为例
/Applications/Firefox.app/Contents/MacOS/firefox
之后在该浏览器中访问 HTTPS 网站时就会把通信时用的密钥记录在所指定的文件中,Wireshark 抓取了 TLS 后,知道加密算法与相应的密钥就能解密出其中的 HTTP 协议内容。
用 Wireshark 捕获包并指定 sslkey 文件
在 Firefox 中访问 https://server.local, 我们在 Wireshark 中抓取包了相应的 TLS 包,并且注意到在 /tmp 目录下生成了 sslkeys.log 文件。
接下来要做的就是让抓取的包与 /tmp/sslkeys.log 进行关联。打开 Wireshark 的 Preferences/Protocols,找到 TLS,然后在 (Pre)-Master-Secret log filename 中指定 sslkey.log 文件
"OK" 后再回到 Wireshark 的主界面,原来的 Application Data 就变绿了(GET / HTTP/1.1 行由于选中了,背景才不是绿色),其中的 HTTP 内容也被解密了
有了这种办法,对于本地调试 HTTPS 也容易了许多。
我们来看下生成的 sslkeys.log 的大致内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# SSL/TLS secrets log file, generated by NSS CLIENT_HANDSHAKE_TRAFFIC_SECRET 0fbfec0c3ad086b91af804ab000dacb648d9bbf7e0017deff1ab8dab15f21572 bac53761d24c6f140a0ea8300cff03de912cfea4c202d2cabd9becb59c5f1a2f SERVER_HANDSHAKE_TRAFFIC_SECRET 0fbfec0c3ad086b91af804ab000dacb648d9bbf7e0017deff1ab8dab15f21572 a8ff51a1d019cf53c5913f3cd7877f85fdea40335f5bf8562b2a777025edf11a CLIENT_HANDSHAKE_TRAFFIC_SECRET 3e81bf06e843c18fb553cefb49e6ce5f3f368a6fe14a35132e7ab612569b13c0 a0442789c313e1fdce4afd14c6e918d6940dfcbe608992911b3197deeada2985 SERVER_HANDSHAKE_TRAFFIC_SECRET 3e81bf06e843c18fb553cefb49e6ce5f3f368a6fe14a35132e7ab612569b13c0 5bb5fbcf633895859e20d958374cd223008fb0266826694e4d6203ddf390175e CLIENT_RANDOM 497f95ff8b12878edb3dfef72e959305f910397e41691eb6e05cfdcd31c7b620 ec9e2d577c115d3659df7daf41ff8fa9aa0656178e93007db0d6413c25c042d7308708c6df060958d2a5f0dc35680cde CLIENT_RANDOM 05105912066dafcd3483d31fea38644b54b8ca33f4dfde408d79c8025e6c9c73 d86e41b363573220bf3de55e4e72083761588834a2d76a0709ed40fb0bc51a366d08213ab0054c012fa03b802aa5b9fa CLIENT_TRAFFIC_SECRET_0 0fbfec0c3ad086b91af804ab000dacb648d9bbf7e0017deff1ab8dab15f21572 ea1fbd105e481754bd06b68a6f487b9ea3c5800a2e1c1d33c5f2d316fe02f69e SERVER_TRAFFIC_SECRET_0 0fbfec0c3ad086b91af804ab000dacb648d9bbf7e0017deff1ab8dab15f21572 7884f5b0fa70e9204c0a974c6355672e2d80646a5538ee52d0da2c1507e0e44e EXPORTER_SECRET 0fbfec0c3ad086b91af804ab000dacb648d9bbf7e0017deff1ab8dab15f21572 1062a72ff38e23379e247175ea6f6830e048dc432b9a5ecd6e71ee512a7aaa10 CLIENT_TRAFFIC_SECRET_0 3e81bf06e843c18fb553cefb49e6ce5f3f368a6fe14a35132e7ab612569b13c0 f56256e26ad11b577e4ab6aeb7100fc58274972ab1cbe32b70f81ae82fcab51e SERVER_TRAFFIC_SECRET_0 3e81bf06e843c18fb553cefb49e6ce5f3f368a6fe14a35132e7ab612569b13c0 7cd64e9e16fd1bda51d3ee4e33c29b47f07364ad568815d88213993abad69e65 EXPORTER_SECRET 3e81bf06e843c18fb553cefb49e6ce5f3f368a6fe14a35132e7ab612569b13c0 7988c01d7883ed8ef8c2be62562118accf05e0336d228a790b8de89db2a00786 ...... |
包括 TLS 的握手过程交换的密钥,随机码以及最后通信用的密钥。
附抓取的包 https_dump.pcap 和相应的 sslkeys.log 文件,有兴趣的话可以用 Wireshark 打开 https_dump.pcap 加上 filter: tcp.port=443 就能显示上面的第一张 Wireshark 图片的内容,如果在 TLS 关联上 sslkeys.log 文件就会显示第二张 Wireshark 图片的内容。
另外:在我们在 Wireshark 关联 sslkeys.log 文件时注意到 Wireshark 还能指定 RSA keys list, 必要时可研究一下它的用法。
链接: