资讯动态

HTTPS协议分析实战:TLS 1.3握手流程、密钥派生与Wireshark抓包解密

发布时间:2026/10/19 4:29:12 来源:尧图企业网站定制
1. 为什么TLS 1.3值得单独拎出来做一次协议分析很多人第一次接触HTTPS抓包分析脑子里想的都是把证书导进去Wireshark一开明文就出来了。这套流程在TLS 1.2时代确实能跑通但到了TLS 1.3你会发现原来那套玩法基本失效了——握手过程被大幅压缩密钥交换和身份认证揉在一起连证书都是加密传输的。我第一次用Wireshark抓TLS 1.3流量时看到ClientHello之后直接就是Application Data中间那些熟悉的ServerHello、Certificate、ServerKeyExchange全都不见了当时确实愣了几秒。这篇内容就是围绕HTTPS协议分析基于TLS 1.3这个主题把TLS 1.3的握手流程、密钥派生机制、抓包分析方法、以及实际排错中会遇到的问题从头到尾捋一遍。适合两类人看一类是做网络协议分析、安全测试的从业者需要搞清楚TLS 1.3到底改了什么、怎么抓、怎么解另一类是后端或运维同学平时配HTTPS只关心证书和协议版本但遇到握手失败、性能异常时想深入理解底层发生了什么。TLS 1.3RFC 8446相比TLS 1.2不是小修小补而是一次结构性重构。它砍掉了RSA密钥交换、删除了大量老旧密码套件、把握手轮次从2-RTT压缩到1-RTT甚至0-RTT同时引入了HKDF密钥派生体系和全新的记录层加密方式。这些改动直接导致传统的抓包解密方法不再适用也让协议分析的门槛提高了不少。下面我会结合实际的抓包场景把每个环节拆开讲。2. TLS 1.3握手的完整链路拆解2.1 从ClientHello到密钥协商1-RTT握手的每一步TLS 1.3的完整握手1-RTT大致是这样的流程客户端先发ClientHello里面带上支持的密码套件列表、key_share扩展包含客户端的临时公钥、supported_versions扩展标明支持TLS 1.3。服务端收到后回一个ServerHello里面选定密码套件、带上自己的key_share公钥。到这里双方其实已经各自拥有了计算共享密钥所需的全部材料。接下来服务端会紧接着发送EncryptedExtensions、Certificate、CertificateVerify、Finished这几条消息注意这些全部是在握手密钥加密下传输的。客户端验证完证书和签名后发送自己的Finished握手完成切换到应用密钥开始传数据。整个过程中最关键的变化是证书消息被加密了。在TLS 1.2里Certificate是明文传输的Wireshark能直接看到证书内容。TLS 1.3把ServerHello之后的所有握手消息都纳入加密范围用的是一个从ECDHE共享密钥派生出来的握手密钥。这就是为什么抓包时看不到证书的原因。我实测过用Wireshark抓一个TLS 1.3的HTTPS请求过滤表达式用tls.handshake.type 1只能看到ClientHello后面的ServerHello虽然能看到因为ServerHello本身是明文但再往后的Certificate就完全看不到了全部显示为Application Data。这个现象是正常的不是抓包工具的问题。2.2 密钥派生HKDF和密钥调度表的工作方式TLS 1.3的密钥派生用的是HKDFHMAC-based Key Derivation Function整个派生过程像一条流水线官方叫密钥调度表Key Schedule。理解这张表是理解TLS 1.3加密机制的核心。流程大致是这样首先通过ECDHE计算出共享密钥Shared Secret然后经过HKDF-Extract生成一个叫Early Secret的中间值如果没有PSK就是全零。接着用derived标签做一次HKDF-Expand-Label得到Derived Secret再和ECDHE共享密钥做HKDF-Extract生成Handshake Secret。从Handshake Secret再派生出手握手阶段的客户端/服务端握手密钥client_handshake_traffic_secret和server_handshake_traffic_secret用于加密握手消息。握手完成后再用Handshake Secret派生出Master Secret进而生成应用阶段的客户端/服务端应用密钥client_application_traffic_secret和server_application_traffic_secret用于加密实际的应用数据。每一步都用到HKDF-Expand-Label标签字符串是固定的比如c hs traffic表示客户端握手流量密钥s ap traffic表示服务端应用流量密钥。这些标签在RFC 8446里有明确定义做协议分析时必须对照着看。注意TLS 1.3的密钥派生是单向的一旦从Handshake Secret派生出Master Secret就无法从Master Secret反推Handshake Secret。这种设计保证了前向安全性但也意味着如果你没能在握手阶段抓到密钥材料后面就无法解密握手消息了。2.3 0-RTT会话恢复快是快但有个坑TLS 1.3支持0-RTT也叫Early Data允许客户端在会话恢复时直接在第一个飞行包里带上应用数据不需要等待握手完成。这对降低延迟效果很明显但有个严重的安全隐患0-RTT数据不具备前向安全性而且容易受到重放攻击。具体来说0-RTT使用的是从PSKPre-Shared Key派生的Early Secret这个密钥在会话建立之前就已经确定了。如果攻击者截获了0-RTT数据包虽然不能解密因为没有PSK但如果攻击者本身是合法客户端就可以重放这些数据包。服务端需要自己实现防重放机制比如用单次票据one-time ticket或者时间窗口限制。我在实际分析中遇到过一个问题某些服务端配置了0-RTT但客户端在第一次连接时并没有使用导致抓包时看到的握手流程和标准1-RTT一样。后来发现是客户端的会话票据过期了或者服务端没有正确下发NewSessionTicket。排查这类问题时要重点看ServerHello之后是否有NewSessionTicket消息以及客户端第二次连接时ClientHello里是否带了pre_shared_key扩展。3. 抓包分析TLS 1.3的实操方法3.1 环境准备Wireshark配置与密钥日志要分析TLS 1.3流量最直接的方法是让客户端导出会话密钥。主流浏览器和很多开发工具都支持通过SSLKEYLOGFILE环境变量导出密钥日志。具体操作是在启动浏览器之前设置环境变量SSLKEYLOGFILE/path/to/sslkeylog.log浏览器会把每次TLS会话的密钥材料写入这个文件。然后在Wireshark里配置打开Preferences - Protocols - TLS在(Pre)-Master-Secret log filename里填入刚才的密钥日志路径。配置完成后Wireshark就能自动解密TLS 1.3流量了。这里有个细节要注意密钥日志文件是追加写入的每次新会话都会追加新的密钥行。如果你在分析过程中重启了浏览器密钥日志会继续追加Wireshark也能识别。但如果密钥日志文件被覆盖或删除之前抓的包就无法解密了。我用的是Chrome和Firefox两者都支持SSLKEYLOGFILE。Firefox还需要在about:config里确认security.ssl.enable_sslkeylogfile为true默认就是true。另外如果你用的是curl可以加--ssl-keylogfile参数指定密钥日志路径。3.2 用Wireshark解密TLS 1.3流量的完整步骤配置好密钥日志后抓包和解密的流程如下启动Wireshark选择网卡开始抓包。设置过滤器tcp.port 443只抓HTTPS流量。在浏览器里访问目标网站触发TLS握手。停止抓包检查Wireshark是否成功解密。如果解密成功你会在Wireshark里看到TLS握手消息的详细内容包括ClientHello里的扩展字段、ServerHello里选定的密码套件、Certificate里的证书链等。如果解密失败通常有几个原因密钥日志路径配置错误、密钥日志文件没有生成、或者抓包时没有覆盖到完整的握手过程。我踩过的一个坑是Wireshark的TLS解密配置需要重启Wireshark才能生效。有一次我配置了密钥日志路径后直接抓包发现还是解不开后来重启Wireshark才正常。另外如果你抓的是已经建立的连接比如浏览器已经打开了网站需要刷新页面重新触发握手否则抓不到密钥交换过程。3.3 没有密钥日志时还能分析什么不是所有场景都能拿到密钥日志。比如分析移动端App的HTTPS流量或者分析第三方服务的流量你没法控制客户端导出密钥。这种情况下能分析的内容就有限了但仍然有一些有价值的信息ClientHello里的SNI虽然TLS 1.3对SNI也做了加密Encrypted Client HelloECH但目前大部分场景下SNI还是明文的。通过SNI可以知道客户端访问的是哪个域名。密码套件列表ClientHello里会列出客户端支持的密码套件可以判断客户端的TLS能力。支持的版本supported_versions扩展会列出客户端支持的TLS版本。key_share扩展可以看到客户端使用的椭圆曲线类型如x25519、secp256r1。ServerHello里的选定套件服务端最终选定的密码套件和密钥交换算法。证书透明度Certificate Transparency虽然证书内容加密了但可以通过CT日志查询域名对应的证书信息。如果确实需要解密第三方流量可以考虑中间人代理方案比如用mitmproxy或Charles作为代理在客户端安装代理的根证书。但这种方式需要客户端信任代理证书对于做了证书固定Certificate Pinning的App可能无效。4. 协议分析中容易踩的坑与排查思路4.1 握手失败从Alert消息定位问题TLS 1.3握手失败时服务端或客户端会发送Alert消息。Alert消息在TLS 1.3里也是加密的除了少数情况但如果你有密钥日志就能看到具体的Alert类型。常见的Alert包括Alert类型含义常见原因handshake_failure握手失败密码套件不匹配、证书验证失败bad_certificate证书错误证书过期、域名不匹配、证书链不完整certificate_required需要客户端证书服务端要求双向认证客户端未提供证书protocol_version协议版本不支持客户端和服务端没有共同支持的TLS版本decrypt_error解密错误密钥不匹配、记录层解密失败illegal_parameter参数非法扩展字段格式错误、密钥共享参数不合法排查握手失败时我通常先看ClientHello和ServerHello的对比客户端支持的密码套件和服务端选定的套件是否匹配supported_versions扩展里是否有交集key_share扩展里的曲线类型是否被服务端支持有一次遇到一个案例客户端只支持TLS 1.3但服务端只配置了TLS 1.2结果ClientHello发出去后服务端直接回了handshake_failure。后来在服务端配置里加上TLS 1.3支持就解决了。这种问题在抓包时看得很清楚ClientHello里supported_versions只有0x0304TLS 1.3ServerHello里选的是0x0303TLS 1.2版本不匹配。4.2 证书验证失败不只是证书过期那么简单证书验证失败是HTTPS分析中最常见的问题之一但原因往往比证书过期复杂。TLS 1.3里证书验证失败的Alert通常是bad_certificate或unknown_ca。常见原因包括证书链不完整服务端只发送了叶子证书没有发送中间证书。客户端无法构建完整的信任链。SNI与证书域名不匹配客户端用SNI指定了域名A但服务端返回的证书是域名B的。证书被吊销证书在CRL或OCSP里被标记为吊销状态。根证书不受信任客户端不信任服务端证书的根CA。证书签名算法不支持比如服务端用了SHA-1签名的证书而客户端已经禁用了SHA-1。排查这类问题时如果能看到Certificate消息就直接检查证书链的完整性、有效期、域名匹配情况。如果看不到没有密钥日志可以通过openssl s_client -connect host:443 -tls1_3命令来测试这个命令会输出详细的握手过程和证书信息。我常用的一个命令是openssl s_client -connect example.com:443 -tls1_3 -servername example.com -showcerts这个命令会显示完整的证书链、选定的密码套件、TLS版本等信息。如果握手失败也会输出具体的错误原因。对于分析TLS 1.3握手问题这个命令比抓包更直接。4.3 性能问题TLS 1.3握手慢在哪里TLS 1.3理论上比TLS 1.2快因为握手轮次减少了。但实际中可能会遇到握手反而变慢的情况。常见原因有密钥交换算法开销TLS 1.3强制使用ECDHE如果客户端和服务端协商的曲线计算开销大比如secp384r1比x25519慢握手时间会增加。证书链过长服务端发送的证书链太长导致握手消息体积大传输时间长。网络延迟1-RTT握手虽然少了一个往返但如果网络RTT本身很高握手时间仍然会很长。服务端配置问题比如服务端没有启用会话恢复每次连接都走完整握手。分析性能问题时我通常会在Wireshark里看每个握手消息的时间戳计算从ClientHello到Finished的总耗时。如果发现某个消息耗时特别长就重点排查那个环节。比如ServerHello到Certificate之间耗时很长可能是服务端在查询OCSP或构建证书链。另外TLS 1.3的会话恢复PSK可以显著降低握手延迟。如果客户端和服务端都支持第二次连接时可以用0-RTT或1-RTT恢复。检查是否启用了会话恢复可以看ServerHello之后是否有NewSessionTicket消息以及客户端第二次ClientHello里是否带了pre_shared_key扩展。5. 从协议分析到实际应用几个值得关注的场景5.1 排查HTTPS拦截与中间人问题在企业网络环境里HTTPS流量经常被中间人代理拦截。TLS 1.3环境下中间人代理需要动态生成证书并且要支持TLS 1.3的握手流程。如果代理不支持TLS 1.3客户端可能会直接握手失败或者降级到TLS 1.2。分析这类问题时重点看Certificate消息里的证书颁发者。如果颁发者不是公共CA而是企业内部的CA就说明流量被拦截了。另外如果客户端和服务端都支持TLS 1.3但实际协商的是TLS 1.2也可能是中间人代理不支持TLS 1.3导致的降级。我遇到过一个案例某企业网络里客户端访问外部HTTPS网站时总是握手失败。抓包发现ClientHello里supported_versions包含TLS 1.3但ServerHello里选的是TLS 1.2而且Certificate里的证书是内部CA签发的。后来确认是中间人代理只支持TLS 1.2而客户端配置了仅TLS 1.3导致握手失败。把客户端配置改成TLS 1.2和1.3都支持就解决了。5.2 分析移动端App的HTTPS流量移动端App的HTTPS流量分析比浏览器复杂因为App通常做了证书固定Certificate Pinning不信任用户安装的代理证书。而且很多App使用自己的网络库如OkHttp、AFNetworkingTLS配置可能和系统默认不同。如果App没有做证书固定可以用mitmproxy或Charles作为代理在设备上安装代理根证书然后抓包分析。如果做了证书固定就需要逆向App找到固定的证书或公钥替换掉或者绕过固定逻辑。这部分涉及逆向工程门槛较高。从协议分析的角度即使不能解密应用数据也可以通过抓包分析App的TLS握手特征支持的密码套件、TLS版本、SNI、会话恢复情况等。这些信息可以帮助判断App的网络行为是否正常比如是否使用了过时的TLS版本、是否频繁重建连接等。5.3 服务端TLS 1.3配置检查清单如果你负责服务端的HTTPS配置以下是一个TLS 1.3配置检查清单可以对照排查协议版本确认服务端启用了TLS 1.3OpenSSL 1.1.1、Nginx 1.13.0、Apache 2.4.36。密码套件TLS 1.3的密码套件和TLS 1.2不同推荐配置TLS_AES_128_GCM_SHA256、TLS_AES_256_GCM_SHA384、TLS_CHACHA20_POLY1305_SHA256。密钥交换推荐使用x25519曲线性能好且安全。会话恢复确认启用了会话票据session ticket并配置了合理的票据生命周期。0-RTT如果启用了0-RTT确保有防重放机制。证书链确保服务端发送完整的证书链包括中间证书。OCSP Stapling启用OCSP Stapling可以减少客户端验证证书的延迟。HSTS配置HSTS头强制客户端使用HTTPS。用openssl s_client -connect host:443 -tls1_3可以快速检查服务端的TLS 1.3配置。输出里会显示选定的密码套件、证书链、会话恢复情况等。如果输出里有Verify return code: 0 (ok)说明证书验证通过。6. 几个我实际踩过的坑和对应的解法6.1 Wireshark解密失败密钥日志格式问题有一次我配置了SSLKEYLOGFILE抓包后Wireshark却提示Unable to decrypt。检查密钥日志文件发现里面确实有内容格式看起来也对。后来发现是Wireshark版本太老不支持TLS 1.3的密钥日志格式。升级到Wireshark 3.0后就正常了。另一个常见问题是密钥日志文件路径包含空格或特殊字符导致Wireshark读取失败。建议把密钥日志文件放在简单路径下比如/tmp/sslkeylog.log或C:\sslkeylog.log。还有一个坑是如果你用的是Chrome的多进程模式SSLKEYLOGFILE环境变量需要设置在启动Chrome的父进程上而不是某个子进程。我通常是在命令行里先export SSLKEYLOGFILE/tmp/sslkeylog.log然后再启动Chrome。6.2 TLS 1.3握手成功但应用数据解密失败这种情况通常是因为密钥日志里缺少应用阶段的密钥。TLS 1.3的密钥日志会记录多个阶段的密钥包括CLIENT_HANDSHAKE_TRAFFIC_SECRET、SERVER_HANDSHAKE_TRAFFIC_SECRET、CLIENT_TRAFFIC_SECRET_0、SERVER_TRAFFIC_SECRET_0等。如果密钥日志只记录了握手阶段的密钥应用数据就无法解密。检查方法是打开密钥日志文件看是否有CLIENT_TRAFFIC_SECRET_0和SERVER_TRAFFIC_SECRET_0这两行。如果没有可能是客户端在握手完成后没有及时写入密钥日志或者密钥日志被截断了。解决方法是确保抓包覆盖完整的连接生命周期包括握手和应用数据传输阶段。6.3 会话恢复导致抓包不完整TLS 1.3的会话恢复PSK会让第二次连接跳过完整的证书交换过程。如果你在分析时发现第二次连接的抓包里没有Certificate消息不要惊讶这是正常的。会话恢复时客户端用pre_shared_key扩展直接复用之前的会话密钥服务端验证PSK后直接进入应用数据传输。如果你需要分析完整的证书交换过程可以清除客户端的会话缓存或者用openssl s_client -no_ticket参数禁用会话票据。在浏览器里可以清除浏览数据包括Cookie和缓存的SSL状态来强制完整握手。6.4 中间人代理导致的证书链异常在企业环境里中间人代理经常会替换证书链。如果你发现Certificate消息里的证书链和预期不符比如缺少中间证书或者根证书是内部CA很可能是代理在作祟。这种情况下客户端的证书验证逻辑可能会失败尤其是做了证书固定的App。排查方法是对比直接连接和通过代理连接时的Certificate消息。如果代理替换了证书直接连接时看到的是公共CA签发的证书通过代理时看到的是内部CA签发的证书。解决方法是把代理的根证书安装到客户端的信任存储里或者配置客户端跳过证书验证仅限测试环境。7. 写在最后一些个人经验TLS 1.3的协议分析确实比TLS 1.2麻烦但核心思路没变理解握手流程、掌握密钥派生机制、学会用工具解密。我自己的习惯是遇到握手问题时先用openssl s_client快速定位再用Wireshark深入分析。openssl s_client的好处是输出直观不需要配置密钥日志适合快速排查。另外TLS 1.3的很多特性如0-RTT、会话恢复在实际部署中需要权衡安全和性能。0-RTT虽然快但重放攻击的风险不能忽视。会话恢复虽然降低了延迟但票据的生命周期和存储安全也需要考虑。做协议分析时不仅要看协议本身还要结合具体的部署场景来理解。最后分享一个小技巧如果你经常需要分析TLS流量可以写一个脚本自动设置SSLKEYLOGFILE并启动浏览器省去每次手动配置的麻烦。我用的是一个小bash脚本把浏览器路径和密钥日志路径作为参数启动前自动清理旧的密钥日志文件避免混淆。这个脚本虽然简单但确实省了不少事。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑