阅读本文前,请先阅读 使用 RSA 密钥交换方式时,使用私钥解密 HTTPS 流量数据。
以下内容来自于 https://firefox-source-docs.mozilla.org/security/nss/legacy/key_log_format/index.html。
外部应用程序可以通过 Key Log 解密 TLS 连接。Wireshark 1.6.0 及以上版本可以使用该日志文件解密数据包。通过 Wireshark -> Preferences -> Protocols -> TLS -> (Pre)-Master-Secret log file,告诉 Wireshark 去哪里寻找 Key 文件。
通过将环境变量 SSLKEYLOGFILE
设置为文件的方式,启用 Key Log。Key Log 文件由一系列行组成。注释行以 # 开头,注释将被忽略。密钥遵循格式 <Label> <space> <ClientRandom> <space> <Secret>
,其中:
<Label>
描述后面的密码<ClientRandom>
是来自于 Client Hello 消息的 32 字节随机值,被编码为 64 个十六进制字符<Secret>
依赖于上面的 LabelLabel 的定义如下:
RSA
:48 字节的预主密钥,被编码为 96 个十六进制字符CLIENT_RANDOM
:48 字节的主密钥,被编码为 96 个十六进制字符(用于 SSL 3.0,TLS 1.0、1.1 和 1.2)CLIENT_EARLY_TRAFFIC_SECRET
:客户端的早期流量密钥(十六进制编码)(用于 TLS 1.3)CLIENT_HANDSHAKE_TRAFFIC_SECRET
:客户端的握手流量密钥(十六进制编码)(用于 TLS 1.3)SERVER_HANDSHAKE_TRAFFIC_SECRET
:服务端的握手流量密钥(十六进制编码)(用于 TLS 1.3)CLIENT_TRAFFIC_SECRET_0
:客户端的第一个应用流量密钥(十六进制编码)(用于 TLS 1.3)SERVER_TRAFFIC_SECRET_0
:服务端的第一个应用流量密钥(十六进制编码)(用于 TLS 1.3)EARLY_EXPORTER_SECRET
:十六进制编码的早期导出器密钥(用于 TLS 1.3)EXPORTER_SECRET
:十六进制编码的导出器密钥RSA
形式允许记录使用 RSA 密钥协商的密码套件,并且这是 Wireshark 1.6.0 支持的第一个形式。它已被 CLIENT_RANDOM
取代,后者可以与其它密钥协商算法(例如基于 Diffie-Hellman 的算法)一起使用,从 Wireshark 1.8.0 起,被支持。
在 TLS 1.3 中,十六进制编码的密钥大小取决于选择的密码套件。对于 SHA256、SHA384、SHA512 分别为 64、96、128 字符。
$ nginx -V
nginx version: nginx/1.18.0 (Ubuntu)
built with OpenSSL 1.1.1f 31 Mar 2020
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-HdenXw/nginx-1.18.0=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-compat --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_sub_module
下载 sslkeylog.c 源代码
编译:
$ cc sslkeylog.c -shared -o libsslkeylog.so -fPIC -ldl
macOS 的使用:
$ cc sslkeylog.c -shared -o libsslkeylog.dylib -fPIC -ldl \
-I/usr/local/opt/openssl@1.1/include \
-L/usr/local/opt/openssl@1.1/lib -lssl
$ DYLD_INSERT_LIBRARIES=./libsslkeylog.dylib DYLD_FORCE_FLAT_NAMESPACE=1 \
SSLKEYLOGFILE=premaster.txt /usr/local/opt/openssl@1.1/bin/openssl ...
如果缺少相应的头文件,那么安装它们,比如在 Ubuntu 上:
$ sudo apt install -y libssl-dev
将编译后的动态连接库拷贝到 /usr/local/lib/
$ mv libsslkeylog.so /usr/local/lib/
/etc/nginx/nginx.conf:
worker_processes auto;
pid /run/nginx.pid;
events {
worker_connections 768;
}
env SSLKEYLOGFILE;
env LD_PRELOAD;
http {
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
sendfile on;
tcp_nodelay on;
keepalive_timeout 15;
include /etc/nginx/mime.types;
default_type application/octet-stream;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_certificate /etc/nginx/cert.pem;
ssl_certificate_key /etc/nginx/prvtkey.pem;
ssl_session_cache off;
ssl_session_tickets off;
server {
listen 443 ssl;
}
}
$ SSLKEYLOGFILE=/tmp/sslkey.log LD_PRELOAD=/usr/local/lib/libsslkeylog.so nginx
$ sudo tcpdump -i lo -w test.pcap
$ curl \
-o /dev/null \
-v \
--tlsv1.2 \
--resolve "test.com:443:127.0.0.1" \
--cacert cacert.pem \
https://test.com/