TLS/SSL 握手过程
目录
TLS/SSL 握手过程
概述
在 HTTPS 通信中,TLS/SSL 握手是建立安全连接的第一个环节。对于逆向工程,理解握手过程是破解 SSL Pinning(证书固定)和进行流量解密(MITM)的基础。
TLS 1.2 握手流程(详细)
握手序列图
sequenceDiagram participant Client as 客户端 participant Server as 服务器 Note over Client,Server: 阶段 1: 协商加密参数 Client->>Server: 1. Client Hello
- TLS 版本
- 加密套件列表
- 客户端随机数 (Random1)
- SNI 扩展 Server->>Client: 2. Server Hello
- 选择的加密套件
- 服务器随机数 (Random2) Server->>Client: 3. Certificate
- 服务器证书链 Server->>Client: 4. Server Hello Done Note over Client,Server: 阶段 2: 密钥交换与验证 Note over Client: 验证服务器证书
- 检查证书链
- 验证签名
- 检查有效期 Note over Client: 生成 Pre-Master Secret Client->>Server: 5. Client Key Exchange
- 用服务器公钥加密的
Pre-Master Secret Note over Client: 计算 Master Secret
= f(Random1, Random2,
Pre-Master Secret) Note over Server: 解密 Pre-Master Secret
计算 Master Secret Client->>Server: 6. Change Cipher Spec
- 通知切换到加密模式 Client->>Server: 7. Finished (加密)
- 握手消息的 HMAC Server->>Client: 8. Change Cipher Spec Server->>Client: 9. Finished (加密) Note over Client,Server: 阶段 3: 加密通信 Client->>Server: Application Data (加密) Server->>Client: Application Data (加密)
sequenceDiagram participant Client as 客户端 participant Server as 服务器 Note over Client,Server: 阶段 1: 协商加密参数 Client->>Server: 1. Client Hello
- TLS 版本
- 加密套件列表
- 客户端随机数 (Random1)
- SNI 扩展 Server->>Client: 2. Server Hello
- 选择的加密套件
- 服务器随机数 (Random2) Server->>Client: 3. Certificate
- 服务器证书链 Server->>Client: 4. Server Hello Done Note over Client,Server: 阶段 2: 密钥交换与验证 Note over Client: 验证服务器证书
- 检查证书链
- 验证签名
- 检查有效期 Note over Client: 生成 Pre-Master Secret Client->>Server: 5. Client Key Exchange
- 用服务器公钥加密的
Pre-Master Secret Note over Client: 计算 Master Secret
= f(Random1, Random2,
Pre-Master Secret) Note over Server: 解密 Pre-Master Secret
计算 Master Secret Client->>Server: 6. Change Cipher Spec
- 通知切换到加密模式 Client->>Server: 7. Finished (加密)
- 握手消息的 HMAC Server->>Client: 8. Change Cipher Spec Server->>Client: 9. Finished (加密) Note over Client,Server: 阶段 3: 加密通信 Client->>Server: Application Data (加密) Server->>Client: Application Data (加密)
sequenceDiagram participant Client as 客户端 participant Server as 服务器 Note over Client,Server: 阶段 1: 协商加密参数 Client->>Server: 1. Client Hello
- TLS 版本
- 加密套件列表
- 客户端随机数 (Random1)
- SNI 扩展 Server->>Client: 2. Server Hello
- 选择的加密套件
- 服务器随机数 (Random2) Server->>Client: 3. Certificate
- 服务器证书链 Server->>Client: 4. Server Hello Done Note over Client,Server: 阶段 2: 密钥交换与验证 Note over Client: 验证服务器证书
- 检查证书链
- 验证签名
- 检查有效期 Note over Client: 生成 Pre-Master Secret Client->>Server: 5. Client Key Exchange
- 用服务器公钥加密的
Pre-Master Secret Note over Client: 计算 Master Secret
= f(Random1, Random2,
Pre-Master Secret) Note over Server: 解密 Pre-Master Secret
计算 Master Secret Client->>Server: 6. Change Cipher Spec
- 通知切换到加密模式 Client->>Server: 7. Finished (加密)
- 握手消息的 HMAC Server->>Client: 8. Change Cipher Spec Server->>Client: 9. Finished (加密) Note over Client,Server: 阶段 3: 加密通信 Client->>Server: Application Data (加密) Server->>Client: Application Data (加密)
sequenceDiagram participant Client as 客户端 participant Server as 服务器 Note over Client,Server: 阶段 1: 协商加密参数 Client->>Server: 1. Client Hello
- TLS 版本
- 加密套件列表
- 客户端随机数 (Random1)
- SNI 扩展 Server->>Client: 2. Server Hello
- 选择的加密套件
- 服务器随机数 (Random2) Server->>Client: 3. Certificate
- 服务器证书链 Server->>Client: 4. Server Hello Done Note over Client,Server: 阶段 2: 密钥交换与验证 Note over Client: 验证服务器证书
- 检查证书链
- 验证签名
- 检查有效期 Note over Client: 生成 Pre-Master Secret Client->>Server: 5. Client Key Exchange
- 用服务器公钥加密的
Pre-Master Secret Note over Client: 计算 Master Secret
= f(Random1, Random2,
Pre-Master Secret) Note over Server: 解密 Pre-Master Secret
计算 Master Secret Client->>Server: 6. Change Cipher Spec
- 通知切换到加密模式 Client->>Server: 7. Finished (加密)
- 握手消息的 HMAC Server->>Client: 8. Change Cipher Spec Server->>Client: 9. Finished (加密) Note over Client,Server: 阶段 3: 加密通信 Client->>Server: Application Data (加密) Server->>Client: Application Data (加密)
1. 协商阶段 (Hello)
- Client Hello: 客户端发送支持的加密套件 (Cipher Suites)、TLS 版本、随机数 (Random1) 以及扩展字段(如 SNI 指明域名)。
- JA3 指纹: 这里的 Client Hello 特征(加密套件顺序、扩展字段等)常被用于识别客户端指纹(JA3),用于反爬虫。
- Server Hello: 服务器选择一组加密套件,发送自己的随机数 (Random2) 和 数字证书。
2. 验证与密钥交换 (Key Exchange)
- 证书验证: 客户端验证服务器发来的证书是否可信(校验证书链、签名、有效期)。
- 密钥生成: 客户端生成"预主密钥" (Pre-Master Secret),用服务器证书中的公钥加密后发送给服务器。
- 注: 在 TLS 1.3 或使用了 PFS (完美前向保密) 的算法中,密钥交换机制更复杂(Diffie-Hellman),不直接传输密钥。
3. 加密通信 (Finished)
- 双方利用 Random1 + Random2 + Pre-Master Secret 计算出最终的 Session Key。
- 后续数据全部用 Session Key 进行对称加密传输。
TLS 1.3 握手流程(简化)
TLS 1.3 大幅简化了握手过程,减少了往返次数(1-RTT):
sequenceDiagram participant Client as 客户端 participant Server as 服务器 Note over Client,Server: TLS 1.3: 1-RTT 握手 Client->>Server: Client Hello
- 支持的加密套件
- 密钥共享 (Key Share)
- 客户端随机数
- SNI 扩展 Note over Server: 选择加密套件
计算共享密钥
生成会话密钥 Server->>Client: Server Hello
- 选择的加密套件
- 密钥共享 (Key Share)
- 服务器随机数 Server->>Client: {Encrypted Extensions}
{Certificate}
{Certificate Verify}
{Finished} Note over Client: 验证证书
计算共享密钥
生成会话密钥 Client->>Server: {Finished} Note over Client,Server: 开始加密通信 Client->>Server: {Application Data} Server->>Client: {Application Data}
sequenceDiagram participant Client as 客户端 participant Server as 服务器 Note over Client,Server: TLS 1.3: 1-RTT 握手 Client->>Server: Client Hello
- 支持的加密套件
- 密钥共享 (Key Share)
- 客户端随机数
- SNI 扩展 Note over Server: 选择加密套件
计算共享密钥
生成会话密钥 Server->>Client: Server Hello
- 选择的加密套件
- 密钥共享 (Key Share)
- 服务器随机数 Server->>Client: {Encrypted Extensions}
{Certificate}
{Certificate Verify}
{Finished} Note over Client: 验证证书
计算共享密钥
生成会话密钥 Client->>Server: {Finished} Note over Client,Server: 开始加密通信 Client->>Server: {Application Data} Server->>Client: {Application Data}
sequenceDiagram participant Client as 客户端 participant Server as 服务器 Note over Client,Server: TLS 1.3: 1-RTT 握手 Client->>Server: Client Hello
- 支持的加密套件
- 密钥共享 (Key Share)
- 客户端随机数
- SNI 扩展 Note over Server: 选择加密套件
计算共享密钥
生成会话密钥 Server->>Client: Server Hello
- 选择的加密套件
- 密钥共享 (Key Share)
- 服务器随机数 Server->>Client: {Encrypted Extensions}
{Certificate}
{Certificate Verify}
{Finished} Note over Client: 验证证书
计算共享密钥
生成会话密钥 Client->>Server: {Finished} Note over Client,Server: 开始加密通信 Client->>Server: {Application Data} Server->>Client: {Application Data}
sequenceDiagram participant Client as 客户端 participant Server as 服务器 Note over Client,Server: TLS 1.3: 1-RTT 握手 Client->>Server: Client Hello
- 支持的加密套件
- 密钥共享 (Key Share)
- 客户端随机数
- SNI 扩展 Note over Server: 选择加密套件
计算共享密钥
生成会话密钥 Server->>Client: Server Hello
- 选择的加密套件
- 密钥共享 (Key Share)
- 服务器随机数 Server->>Client: {Encrypted Extensions}
{Certificate}
{Certificate Verify}
{Finished} Note over Client: 验证证书
计算共享密钥
生成会话密钥 Client->>Server: {Finished} Note over Client,Server: 开始加密通信 Client->>Server: {Application Data} Server->>Client: {Application Data}
TLS 1.3 主要改进:
- 1-RTT: 只需一次往返即可建立加密连接(TLS 1.2 需要 2-RTT)
- 0-RTT: 恢复会话时可实现零往返(但有重放攻击风险)
- 密钥交换: 仅支持 PFS (完美前向保密) 算法,如 ECDHE
- 去除弱加密: 移除 RSA 密钥交换、静态 DH 等不安全算法
逆向中的关键点
1. 为什么 Charles/Fiddler 抓不到 HTTPS 包?
因为中间人(Charles)发给客户端的是 Charles 自己签发的伪造证书。
- 如果客户端(APP/浏览器)不信任 Charles 的根证书,握手就会在"证书验证"阶段失败,连接断开。
MITM 攻击原理图
sequenceDiagram participant Client as 客户端
(APP/浏览器) participant Proxy as 中间人代理
(Charles/Burp) participant Server as 目标服务器 Note over Client,Server: 正常 HTTPS 连接(无代理) Client->>Server: 直接建立 TLS 连接 Server->>Client: 返回真实服务器证书 Note over Client: 验证通过,建立加密连接 Note over Client,Server: MITM 攻击场景 Client->>Proxy: Client Hello (访问 api.example.com) Proxy->>Server: 转发 Client Hello Server->>Proxy: Server Hello + 真实证书 Note over Proxy: 生成伪造证书
- 签发者: Charles CA
- 主题: api.example.com Proxy->>Client: 返回伪造证书 alt 客户端未信任 Charles CA Note over Client: ❌ 证书验证失败
连接中断 else 客户端已信任 Charles CA Note over Client: ✅ 证书验证通过
建立加密连接 Client->>Proxy: 加密数据 (用伪造证书公钥) Note over Proxy: 解密客户端数据
查看/修改
重新加密 Proxy->>Server: 转发到服务器 (用真实证书) Server->>Proxy: 加密响应 Note over Proxy: 解密服务器响应
查看/修改
重新加密 Proxy->>Client: 返回给客户端 end
sequenceDiagram participant Client as 客户端
(APP/浏览器) participant Proxy as 中间人代理
(Charles/Burp) participant Server as 目标服务器 Note over Client,Server: 正常 HTTPS 连接(无代理) Client->>Server: 直接建立 TLS 连接 Server->>Client: 返回真实服务器证书 Note over Client: 验证通过,建立加密连接 Note over Client,Server: MITM 攻击场景 Client->>Proxy: Client Hello (访问 api.example.com) Proxy->>Server: 转发 Client Hello Server->>Proxy: Server Hello + 真实证书 Note over Proxy: 生成伪造证书
- 签发者: Charles CA
- 主题: api.example.com Proxy->>Client: 返回伪造证书 alt 客户端未信任 Charles CA Note over Client: ❌ 证书验证失败
连接中断 else 客户端已信任 Charles CA Note over Client: ✅ 证书验证通过
建立加密连接 Client->>Proxy: 加密数据 (用伪造证书公钥) Note over Proxy: 解密客户端数据
查看/修改
重新加密 Proxy->>Server: 转发到服务器 (用真实证书) Server->>Proxy: 加密响应 Note over Proxy: 解密服务器响应
查看/修改
重新加密 Proxy->>Client: 返回给客户端 end
sequenceDiagram participant Client as 客户端
(APP/浏览器) participant Proxy as 中间人代理
(Charles/Burp) participant Server as 目标服务器 Note over Client,Server: 正常 HTTPS 连接(无代理) Client->>Server: 直接建立 TLS 连接 Server->>Client: 返回真实服务器证书 Note over Client: 验证通过,建立加密连接 Note over Client,Server: MITM 攻击场景 Client->>Proxy: Client Hello (访问 api.example.com) Proxy->>Server: 转发 Client Hello Server->>Proxy: Server Hello + 真实证书 Note over Proxy: 生成伪造证书
- 签发者: Charles CA
- 主题: api.example.com Proxy->>Client: 返回伪造证书 alt 客户端未信任 Charles CA Note over Client: ❌ 证书验证失败
连接中断 else 客户端已信任 Charles CA Note over Client: ✅ 证书验证通过
建立加密连接 Client->>Proxy: 加密数据 (用伪造证书公钥) Note over Proxy: 解密客户端数据
查看/修改
重新加密 Proxy->>Server: 转发到服务器 (用真实证书) Server->>Proxy: 加密响应 Note over Proxy: 解密服务器响应
查看/修改
重新加密 Proxy->>Client: 返回给客户端 end
sequenceDiagram participant Client as 客户端
(APP/浏览器) participant Proxy as 中间人代理
(Charles/Burp) participant Server as 目标服务器 Note over Client,Server: 正常 HTTPS 连接(无代理) Client->>Server: 直接建立 TLS 连接 Server->>Client: 返回真实服务器证书 Note over Client: 验证通过,建立加密连接 Note over Client,Server: MITM 攻击场景 Client->>Proxy: Client Hello (访问 api.example.com) Proxy->>Server: 转发 Client Hello Server->>Proxy: Server Hello + 真实证书 Note over Proxy: 生成伪造证书
- 签发者: Charles CA
- 主题: api.example.com Proxy->>Client: 返回伪造证书 alt 客户端未信任 Charles CA Note over Client: ❌ 证书验证失败
连接中断 else 客户端已信任 Charles CA Note over Client: ✅ 证书验证通过
建立加密连接 Client->>Proxy: 加密数据 (用伪造证书公钥) Note over Proxy: 解密客户端数据
查看/修改
重新加密 Proxy->>Server: 转发到服务器 (用真实证书) Server->>Proxy: 加密响应 Note over Proxy: 解密服务器响应
查看/修改
重新加密 Proxy->>Client: 返回给客户端 end
2. Certificate Pinning (证书固定)
为了防止中间人攻击,许多 APP 内置了服务器证书的指纹(Hash),在 TLS 握手时,不仅验证证书是否可信,还要比对公钥 Hash 是否与内置的一致。如果仅仅在系统中安装了 Charles 证书,APP 发现 Hash 不匹配,依然会报错。
Certificate Pinning 验证流程
flowchart TD
A[开始 TLS 握手] --> B[接收服务器证书]
B --> C{系统证书链验证}
C -->|失败| D[❌ 连接失败]
C -->|通过| E{Certificate Pinning
启用?}
E -->|未启用| F[✅ 建立连接]
E -->|已启用| G[提取证书公钥]
G --> H[计算公钥 Hash
SHA256/SHA1]
H --> I{Hash 是否匹配
内置指纹?}
I -->|匹配| F
I -->|不匹配| J[❌ Pinning 验证失败
连接中断]
style D fill:#ff6b6b
style F fill:#51cf66
style J fill:#ff6b6bflowchart TD
A[开始 TLS 握手] --> B[接收服务器证书]
B --> C{系统证书链验证}
C -->|失败| D[❌ 连接失败]
C -->|通过| E{Certificate Pinning
启用?}
E -->|未启用| F[✅ 建立连接]
E -->|已启用| G[提取证书公钥]
G --> H[计算公钥 Hash
SHA256/SHA1]
H --> I{Hash 是否匹配
内置指纹?}
I -->|匹配| F
I -->|不匹配| J[❌ Pinning 验证失败
连接中断]
style D fill:#ff6b6b
style F fill:#51cf66
style J fill:#ff6b6bflowchart TD
A[开始 TLS 握手] --> B[接收服务器证书]
B --> C{系统证书链验证}
C -->|失败| D[❌ 连接失败]
C -->|通过| E{Certificate Pinning
启用?}
E -->|未启用| F[✅ 建立连接]
E -->|已启用| G[提取证书公钥]
G --> H[计算公钥 Hash
SHA256/SHA1]
H --> I{Hash 是否匹配
内置指纹?}
I -->|匹配| F
I -->|不匹配| J[❌ Pinning 验证失败
连接中断]
style D fill:#ff6b6b
style F fill:#51cf66
style J fill:#ff6b6bflowchart TD
A[开始 TLS 握手] --> B[接收服务器证书]
B --> C{系统证书链验证}
C -->|失败| D[❌ 连接失败]
C -->|通过| E{Certificate Pinning
启用?}
E -->|未启用| F[✅ 建立连接]
E -->|已启用| G[提取证书公钥]
G --> H[计算公钥 Hash
SHA256/SHA1]
H --> I{Hash 是否匹配
内置指纹?}
I -->|匹配| F
I -->|不匹配| J[❌ Pinning 验证失败
连接中断]
style D fill:#ff6b6b
style F fill:#51cf66
style J fill:#ff6b6bPinning 实现示例
Android (OkHttp):
| |
iOS (Swift):
| |
[Reverse Engineering Context] 绕过 Pinning
Pinning 逻辑通常在网络库(OkHttp, AFNetworking)或 Native 层(OpenSSL, BoringSSL)的回调中。
flowchart TD
A[识别 Pinning 机制] --> B{Pinning 层级}
B -->|Java/Kotlin 层| C[Hook 网络库]
B -->|Native 层| D[Hook SSL 库]
B -->|多层防护| E[组合绕过]
C --> C1[方案 1: Hook TrustManager]
C1 --> C1A["Hook checkServerTrusted()
直接返回 true"]
C --> C2[方案 2: Hook OkHttp]
C2 --> C2A["Hook CertificatePinner.check()
跳过验证"]
D --> D1[方案 3: Hook OpenSSL]
D1 --> D1A["Hook SSL_CTX_set_verify()
禁用验证回调"]
D --> D2[方案 4: Hook BoringSSL]
D2 --> D2A["Hook ssl_verify_peer_cert()
强制返回成功"]
E --> E1[Frida 多点 Hook]
E1 --> E1A[同时 Hook Java + Native 层]
C1A --> F[✅ 绕过成功]
C2A --> F
D1A --> F
D2A --> F
E1A --> F
style F fill:#51cf66flowchart TD
A[识别 Pinning 机制] --> B{Pinning 层级}
B -->|Java/Kotlin 层| C[Hook 网络库]
B -->|Native 层| D[Hook SSL 库]
B -->|多层防护| E[组合绕过]
C --> C1[方案 1: Hook TrustManager]
C1 --> C1A["Hook checkServerTrusted()
直接返回 true"]
C --> C2[方案 2: Hook OkHttp]
C2 --> C2A["Hook CertificatePinner.check()
跳过验证"]
D --> D1[方案 3: Hook OpenSSL]
D1 --> D1A["Hook SSL_CTX_set_verify()
禁用验证回调"]
D --> D2[方案 4: Hook BoringSSL]
D2 --> D2A["Hook ssl_verify_peer_cert()
强制返回成功"]
E --> E1[Frida 多点 Hook]
E1 --> E1A[同时 Hook Java + Native 层]
C1A --> F[✅ 绕过成功]
C2A --> F
D1A --> F
D2A --> F
E1A --> F
style F fill:#51cf66flowchart TD
A[识别 Pinning 机制] --> B{Pinning 层级}
B -->|Java/Kotlin 层| C[Hook 网络库]
B -->|Native 层| D[Hook SSL 库]
B -->|多层防护| E[组合绕过]
C --> C1[方案 1: Hook TrustManager]
C1 --> C1A["Hook checkServerTrusted()
直接返回 true"]
C --> C2[方案 2: Hook OkHttp]
C2 --> C2A["Hook CertificatePinner.check()
跳过验证"]
D --> D1[方案 3: Hook OpenSSL]
D1 --> D1A["Hook SSL_CTX_set_verify()
禁用验证回调"]
D --> D2[方案 4: Hook BoringSSL]
D2 --> D2A["Hook ssl_verify_peer_cert()
强制返回成功"]
E --> E1[Frida 多点 Hook]
E1 --> E1A[同时 Hook Java + Native 层]
C1A --> F[✅ 绕过成功]
C2A --> F
D1A --> F
D2A --> F
E1A --> F
style F fill:#51cf66flowchart TD
A[识别 Pinning 机制] --> B{Pinning 层级}
B -->|Java/Kotlin 层| C[Hook 网络库]
B -->|Native 层| D[Hook SSL 库]
B -->|多层防护| E[组合绕过]
C --> C1[方案 1: Hook TrustManager]
C1 --> C1A["Hook checkServerTrusted()
直接返回 true"]
C --> C2[方案 2: Hook OkHttp]
C2 --> C2A["Hook CertificatePinner.check()
跳过验证"]
D --> D1[方案 3: Hook OpenSSL]
D1 --> D1A["Hook SSL_CTX_set_verify()
禁用验证回调"]
D --> D2[方案 4: Hook BoringSSL]
D2 --> D2A["Hook ssl_verify_peer_cert()
强制返回成功"]
E --> E1[Frida 多点 Hook]
E1 --> E1A[同时 Hook Java + Native 层]
C1A --> F[✅ 绕过成功]
C2A --> F
D1A --> F
D2A --> F
E1A --> F
style F fill:#51cf66绕过方法:
- Android (Java 层):
Hook
javax.net.ssl.X509TrustManager.checkServerTrusted,让其永远不抛异常。
| |
- Native 层 (so 修改):
Hook SSL 库的验证函数,如
SSL_CTX_set_custom_verify或直接 Hook 握手结果。
| |
3. 双向认证 (Mutual TLS / mTLS)
服务器要求客户端也出示证书。
- 表现: 抓包看到服务器返回
400 Bad Request (No Client Certificate)。 - 逆向: 需要从 APK/IPA 或设备文件系统中提取出
.p12或.bks客户端证书,并导入到 Charles/Burp 中。
总结
TLS 握手是 HTTP 之前的“暗号对接”。
- 正向: 保证数据不被窃听和篡改。
- 逆向: 我们就是那个“窃听者”和“篡改者”。因此,我们的工作重心是让自己成为客户端信任的“中间人”(绕过证书校验/Pinning),或者直接拿到通信密钥(Hook OpenSSL)。
相关内容
如果这篇文章对你有帮助,请我喝杯咖啡吧~
支付宝
微信