# 第六章:TLS 协议深入解析 > "TLS 是互联网安全的基石,每一次 HTTPS 请求背后都有它的身影。" ```{mermaid} 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 最佳实践 ```nginx 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 编程 ```python 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 扩展将进一步保护用户隐私