第六章:TLS 协议深入解析
“TLS 是互联网安全的基石,每一次 HTTPS 请求背后都有它的身影。”
mindmap
root((TLS 协议))
演进历史
SSL 3.0
TLS 1.0/1.1
TLS 1.2
TLS 1.3
握手流程
密钥交换
身份验证
密码协商
安全特性
前向保密
0-RTT
AEAD
mTLS
双向认证
Service Mesh
SPIFFE
6.1 TLS 的演进
版本 |
年份 |
状态 |
说明 |
|---|---|---|---|
SSL 2.0 |
1995 |
❌ 废弃 |
严重安全缺陷 |
SSL 3.0 |
1996 |
❌ 废弃 |
POODLE 攻击 |
TLS 1.0 |
1999 |
❌ 废弃 |
BEAST 攻击 |
TLS 1.1 |
2006 |
❌ 废弃 |
不支持 AEAD |
TLS 1.2 |
2008 |
✅ 广泛使用 |
支持 GCM、SHA-256 |
TLS 1.3 |
2018 |
✅ 推荐 |
1-RTT、移除不安全算法 |
6.2 TLS 1.2 握手流程
客户端 服务器
│ │
│ 1. ClientHello │
│ (支持的密码套件、随机数、SNI) │
│──────────────────────────────────────────────▶│
│ │
│ 2. ServerHello │
│ (选择的密码套件、随机数) │
│ 3. Certificate (服务器证书) │
│ 4. ServerKeyExchange (DH 参数) │
│ 5. CertificateRequest (mTLS 时) │
│ 6. ServerHelloDone │
│◀──────────────────────────────────────────────│
│ │
│ 7. Certificate (客户端证书, mTLS 时) │
│ 8. ClientKeyExchange (DH 公钥) │
│ 9. CertificateVerify (mTLS 时) │
│ 10. ChangeCipherSpec │
│ 11. Finished │
│──────────────────────────────────────────────▶│
│ │
│ 12. ChangeCipherSpec │
│ 13. Finished │
│◀──────────────────────────────────────────────│
│ │
│ ═══════ 加密通信开始(2-RTT)═══════ │
密码套件(Cipher Suite)
TLS 1.2 密码套件格式:TLS_密钥交换_WITH_加密算法_哈希算法
推荐的 TLS 1.2 密码套件:
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
│ │ │ │ │ │
│ │ │ │ │ └── 哈希:SHA-384
│ │ │ │ └─────── 模式:GCM(认证加密)
│ │ │ └──────────── 加密:AES-256
│ │ └───────────────────── 认证:RSA 证书
│ └──────────────────────────── 密钥交换:ECDHE(前向保密)
└───────────────────────────────── 协议:TLS
6.3 TLS 1.3 的改进
TLS 1.3 做了大幅简化和安全增强:
客户端 服务器
│ │
│ 1. ClientHello │
│ (支持的密码套件、密钥共享、SNI) │
│──────────────────────────────────────────────▶│
│ │
│ 2. ServerHello (密钥共享) │
│ 3. EncryptedExtensions │
│ 4. Certificate │
│ 5. CertificateVerify │
│ 6. Finished │
│◀──────────────────────────────────────────────│
│ │
│ 7. Finished │
│──────────────────────────────────────────────▶│
│ │
│ ═══════ 加密通信开始(1-RTT)═══════ │
TLS 1.3 vs 1.2
特性 |
TLS 1.2 |
TLS 1.3 |
|---|---|---|
握手延迟 |
2-RTT |
1-RTT(支持 0-RTT) |
密钥交换 |
RSA/DHE/ECDHE |
仅 ECDHE/DHE |
对称加密 |
CBC/GCM |
仅 AEAD(GCM/ChaCha20) |
哈希算法 |
MD5/SHA-1/SHA-256 |
仅 SHA-256/SHA-384 |
前向保密 |
可选 |
强制 |
0-RTT |
不支持 |
支持(有重放风险) |
压缩 |
支持(CRIME 攻击) |
移除 |
重协商 |
支持 |
移除 |
TLS 1.3 密码套件
TLS 1.3 只有 5 个密码套件:
TLS_AES_256_GCM_SHA384 ← 推荐
TLS_AES_128_GCM_SHA256 ← 推荐
TLS_CHACHA20_POLY1305_SHA256 ← 移动设备推荐
TLS_AES_128_CCM_SHA256
TLS_AES_128_CCM_8_SHA256
6.4 SNI 与 ALPN
SNI(Server Name Indication)
SNI 允许客户端在 TLS 握手时指定要访问的主机名,使同一 IP 可以托管多个 HTTPS 站点:
ClientHello:
server_name: example.com ← SNI 扩展
注意:SNI 是明文传输的!
ECH(Encrypted Client Hello)是 TLS 1.3 的扩展,
可以加密 SNI,防止网络监控者知道你访问了哪个网站。
ALPN(Application-Layer Protocol Negotiation)
ALPN 在 TLS 握手时协商应用层协议:
ClientHello:
alpn: ["h2", "http/1.1"] ← 支持 HTTP/2 和 HTTP/1.1
ServerHello:
alpn: "h2" ← 选择 HTTP/2
6.5 TLS 常见攻击
攻击 |
年份 |
影响 |
防御 |
|---|---|---|---|
BEAST |
2011 |
TLS 1.0 CBC |
升级到 TLS 1.2+ |
CRIME |
2012 |
TLS 压缩 |
禁用 TLS 压缩 |
Heartbleed |
2014 |
OpenSSL 内存泄露 |
更新 OpenSSL |
POODLE |
2014 |
SSL 3.0 |
禁用 SSL 3.0 |
FREAK |
2015 |
出口级密码 |
禁用弱密码套件 |
Logjam |
2015 |
弱 DH 参数 |
使用 2048+ 位 DH |
ROBOT |
2017 |
RSA 密钥交换 |
使用 ECDHE |
DROWN |
2016 |
SSLv2 跨协议 |
禁用 SSLv2 |
6.6 Nginx TLS 最佳实践
server {
listen 443 ssl http2;
server_name example.com;
# 证书
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
# 协议版本:仅 TLS 1.2 和 1.3
ssl_protocols TLSv1.2 TLSv1.3;
# 密码套件(服务器优先)
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305';
# DH 参数(2048 位以上)
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/nginx/ssl/chain.pem;
# Session 缓存
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# HSTS(HTTP Strict Transport Security)
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# 安全头
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
add_header X-XSS-Protection "1; mode=block";
}
6.7 Python TLS 编程
import ssl
import socket
def create_tls_client(hostname: str, port: int = 443) -> ssl.SSLSocket:
"""创建安全的 TLS 客户端连接"""
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
# 设置最低 TLS 版本
context.minimum_version = ssl.TLSVersion.TLSv1_2
# 加载系统 CA 证书
context.load_default_certs()
# 启用证书验证
context.verify_mode = ssl.CERT_REQUIRED
context.check_hostname = True
# 创建连接
sock = socket.create_connection((hostname, port))
tls_sock = context.wrap_socket(sock, server_hostname=hostname)
# 打印连接信息
print(f"协议版本: {tls_sock.version()}")
print(f"密码套件: {tls_sock.cipher()}")
cert = tls_sock.getpeercert()
print(f"证书主体: {cert['subject']}")
print(f"证书有效期: {cert['notBefore']} - {cert['notAfter']}")
return tls_sock
# mTLS 客户端
def create_mtls_client(hostname: str, port: int,
client_cert: str, client_key: str,
ca_cert: str) -> ssl.SSLSocket:
"""创建 mTLS 客户端连接"""
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
context.minimum_version = ssl.TLSVersion.TLSv1_2
# 加载客户端证书
context.load_cert_chain(client_cert, client_key)
# 加载 CA 证书
context.load_verify_locations(ca_cert)
context.verify_mode = ssl.CERT_REQUIRED
context.check_hostname = True
sock = socket.create_connection((hostname, port))
return context.wrap_socket(sock, server_hostname=hostname)
6.8 小结
TLS 1.3 是当前推荐版本:1-RTT 握手、强制前向保密、仅 AEAD 加密
mTLS 是微服务安全和零信任的基础,SPIFFE/SPIRE 自动化了 mTLS 证书管理
正确配置 TLS 至关重要:禁用旧版本、选择安全密码套件、启用 HSTS
TLS 1.3 的 ECH 扩展将进一步保护用户隐私