184 lines
6.1 KiB
Markdown
184 lines
6.1 KiB
Markdown
|
|
---
|
|||
|
|
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 历史安全漏洞
|