Files
2026-05-24 11:42:38 +08:00

184 lines
6.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
tags: [计算机网络, HTTPS, TLS, 证书, PKI]
create time: 2026-05-18 03:00
---
# HTTPS 与 TLS 握手
## 概述
HTTPS = HTTP over TLS(Transport Layer Security)。TLS 在 TCP 和应用层之间插入一个加密通道,确保通信的机密性、完整性和对端身份验证。理解 TLS 握手过程是排查 SSL 错误的核心能力。
## TLS 在协议栈中的位置
```
┌─────────────┐
│ HTTP │ ← 应用层
├─────────────┤
│ TLS │ ← "加密壳" — 透明包装下层数据
├─────────────┤
│ TCP │ ← 可靠传输
├─────────────┤
│ IP │ ← 路由
└─────────────┘
```
## TLS 握手流程(TLS 1.3)
### 完整交互序列
```mermaid
sequenceDiagram
participant C as Client
participant S as Server
Note over C,S: Phase 1: Key Exchange (Full Handshake)
C->>S: ClientHello<br/>• TLS version (1.3)<br/>• Cipher suites (pref order)<br/>• Random bytes<br/>• PSK/session ticket (optional)<br/>• Extensions (ALPN, SNI...)
S-->>C: ServerHello<br/>• Selected cipher suite<br/>• Random bytes<br/>• Server's key share (ephemeral ECDHE)
S->>S: Send certificate + cert_chain
S->>C: CertificateRequest (optional)
S->>C: ServerKeyExchange (if needed)
S->>C: ServerFinished
C->>C: Verify cert chain → CA ✓
C->>S: ClientKeyExchange (key share)
C->>C: Compute shared secret (ECDHE)
C->>S: ChangeCipherSpec (implicit in 1.3)
C->>S: ClientFinished
Note over C,S: ← Encryption Enabled ✨ -->
C->>S: Application data (HTTP Request) 🔒
S->>C: Application data (HTTP Response) 🔒
```
### TLS 1.3 vs TLS 1.2 对比
| 特性 | TLS 1.2 | TLS 1.3 |
|------|---------|---------|
| **往返次数** | 2 RTT (或 1 RTT with session resumption) | **1 RTT** (0 RTT if resumed) ⚡ |
| 密钥交换 | RSA / DHE / ECDHE | **仅 ECDHE** (前向安全强制) |
| Cipher Suites | ~30+ 种选择 | **仅 4 种** (AES-GCM, ChaCha20-Poly1305) |
| 压缩 | ✅ (导致 CRIME 漏洞) | ❌ **已禁用** |
| 重协商 | ✅ | ❌ (改用 NewSession Ticket) |
| 静态 RSA 密钥交换 | ✅ | ❌ **已移除** |
| CBC 模式密文 | ✅ | ❌ **已移除** |
| Export ciphers | ✅ | ❌ **已移除** |
| Renegotiation | ✅ | ❌ (用 renegotiation_info 扩展替代) |
> [!tip] TLS 1.3 为什么更快?
> TLS 1.2: ClientHello → ServerHello → Certificate → ServerKeyExchange → ... → ClientKeyExchange → Finished = **2 full RTTs**
>
> TLS 1.3: ClientHello (含 client key share) → ServerHello (含 server key share) + Certificate + Finished = **1 RTT**
>
> 因为客户端在第一个包中就携带了自己的密钥共享信息,无需等待服务器回复后再计算。
## Cipher Suite 详解
TLS 1.3 只有 4 个 Cipher Suites:
| 编号 | Cipher Suite | KEM | AEAD | HKDF |
|------|-------------|-----|------|------|
| TLS_AES_128_GCM_SHA256 | AES-128-GCM | X25519 | AES-128-GCM | SHA256 |
| TLS_AES_256_GCM_SHA384 | AES-256-GCM | X25519 | AES-256-GCM | SHA384 |
| TLS_CHACHA20_POLY1305_SHA256 | ChaCha20-Poly1305 | X25519 | ChaCha20-Poly1305 | SHA256 |
| TLS_AES_128_CCM_SHA256 | AES-128-CCM | X25519 | AES-128-CCM | SHA256 |
**Go 中默认偏好顺序:** `TLS_AES_256_GCM_SHA384 > TLS_AES_128_GCM_SHA256 > TLS_CHACHA20_POLY1305_SHA256`
## 证书链验证流程
```mermaid
flowchart TD
Cert["Server Certificate<br/>CN = example.com"] -->|"issued by"| Inter["Intermediate CA<br/>ISRG Root X1"]
Inter -->|"issued by"| Root["Root CA<br/>DigiCert Global Root G2"]
Root -->|"self-signed"| Root
Client["Client 浏览器"] -->|"验证:"| V1["1. 签名是否由上层CA签发?"]
V1 -->|"是"| V2["2. CN/SAN 是否匹配域名?"]
V2 -->|"是"| V3["3. 是否过期?"]
V3 -->|"是"| V4["4. 是否在 OCSP/CRL 吊销列表中?"]
V4 -->|"是"| V5["5. 根证书是否在信任库中?"]
V5 -->|"是"| TRUSTED["✅ 信任!"]
style TRUSTED fill:#98FB98,color:#000
```
## 实际调试命令
```bash
# 查看服务器支持的 TLS 版本和 Cipher Suites
$ openssl s_client -connect example.com:443 -tls1_3
CONNECTED(00000003)
Protocol : TLSv1.3
Cipher : TLS_AES_256_GCM_SHA384
Certificate chain:
0 s:CN = example.com
i:C = US, O = DigiCert Inc, CN = DigiCert TLS Hybrid ECC_SHA384 2020 CA1
# 指定特定 Cipher 测试
$ openssl s_client -connect example.com:443 \
-cipher 'ECDHE-ECDSA-AES256-GCM-SHA384'
# 获取证书信息
$ openssl x509 -in cert.pem -noout -dates -subject -issuer
subject=CN = example.com
notBefore=Jan 1 00:00:00 2025 GMT
notAfter=Jan 1 00:00:00 2026 GMT
# 检查 OCSP 状态
$ curl -vI https://example.com
< HTTP/2 200
< alt-s: h3=":443"; ma=86400
< alt-s: h2=":443"; ma=86400
# Go 中自定义证书验证
import "crypto/tls"
config := &tls.Config{
InsecureSkipVerify: false, // 生产环境永远为 false
MinVersion: tls.VersionTLS13,
}
conn, _ := tls.Dial("tcp", "example.com:443", config)
```
## Go 标准库中的 TLS
```go
// 创建安全的 TLS 配置
var DefaultTLSConfig = tls.Config{
MinVersion: tls.VersionTLS12, // 最低支持 TLS 1.2
PreferServerCipherSuites: true,
}
// http.Server 自动启用 TLS
srv := &http.Server{
Addr: ":443",
Handler: handler,
TLSConfig: &tls.Config{
MinVersion: tls.VersionTLS13,
NextProtos: []string{"h2", "http/1.1"}, // ALPN
},
}
srv.ListenAndServeTLS("cert.pem", "key.pem")
// 或 Let's Encrypt (auto TLS)
import "crypto/tls"
mux.HandleFunc("/", handler)
go http.ListenAndServe(":80", nil) // ACME Challenge
go http.ListenAndServeTLS(":443", "", "", &http.Server{
Handler: mux,
TLSConfig: &tls.Config{
GetCertificate: autoTLSManager.GetCertificate,
NextProtos: []string{"h2", "http/1.1"},
},
})
```
## 关联笔记
- [[hhs/NETWORK/HTTP/3与QUIC]] — QUIC 内置 TLS 1.3
- [[hhs/NETWORK/DNS原理与优化]] — SNI 扩展帮助 DNS 和 CDN 调度
- [[hhs/NETWORK/SSL Strip-Heartbleed]] — TLS 历史安全漏洞