第六章: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 扩展将进一步保护用户隐私