TLS 概述

SSL 与 TLS 的历史演进

SSL(Secure Sockets Layer,安全套接层)由网景公司(Netscape)于 1990 年代初开发,旨在为网络通信提供加密和身份验证。经过多个版本迭代:

  • SSL 2.0(1994):首个公开发布版本,存在多项安全缺陷
  • SSL 3.0(1996):重写设计,但已于 2015 年被 RFC 7568 明确禁止1

TLS(Transport Layer Security,传输层安全)是 SSL 的标准化继任者:

版本发布时间状态主要改进
TLS 1.01999已废弃(RFC 7562)基于 SSL 3.0,差异微小
TLS 1.12006已废弃(RFC 7562)增加 CBC 攻击防护
TLS 1.22008仍广泛使用支持 AES-GCM、SHA-256、扩展验证
TLS 1.32018推荐使用1-RTT 握手、0-RTT、移除弱算法

关键里程碑:2020 年 3 月,TLS 1.0/1.1 被各大浏览器正式弃用2

TLS 的三大安全目标

TLS 协议通过组合使用多种密码学技术,同时实现三个核心安全目标:

  1. 机密性(Confidentiality):通过对称加密确保只有通信双方能读取通信内容,防止窃听。

  2. 完整性(Integrity):通过 MAC(消息认证码)或 AEAD(Authenticated Encryption with Associated Data)机制防止数据被篡改。

  3. 认证(Authentication):通过数字证书验证通信对端的真实身份,防止身份伪装。

┌─────────────────────────────────────────────────────────────┐
│                      TLS 安全目标                            │
├─────────────────────────────────────────────────────────────┤
│  机密性  │  对称加密(AES-GCM、ChaCha20)  │  防止窃听        │
│  完整性  │  MAC/AEAD(HMAC、Poly1305)     │  防止篡改        │
│  认证    │  数字证书 + 非对称签名           │  防止伪造身份    │
└─────────────────────────────────────────────────────────────┘

TLS 握手详解

TLS 1.2 握手(2-RTT)

TLS 1.2 采用 RSA 或 Diffie-Hellman 密钥交换,完整握手需要两轮往返(2 RTT):

Client                                          Server
   │                                               │
   │────────── ClientHello ────────────────────────▶│
   │          (支持的密码套件列表、随机数)           │
   │                                               │
   │◀──────── ServerHello ─────────────────────────│
   │          (选定的密码套件、随机数)               │
   │◀──────── Certificate ─────────────────────────│
   │          (服务器证书链)                        │
   │◀──────── ServerKeyExchange ──────────────────│
   │          (DH 参数 / RSA 加密的预主密钥)        │
   │◀──────── CertificateRequest ─────────────────│
   │          (可选:请求客户端证书)                 │
   │◀──────── ServerHelloDone ─────────────────────│
   │                                               │
   │────────── ClientKeyExchange ──────────────────▶│
   │          (DH 公钥 / 加密的预主密钥)            │
   │────────── CertificateVerify ─────────────────▶│
   │          (可选:用客户端私钥签名)               │
   │────────── ChangeCipherSpec ──────────────────▶│
   │────────── Finished ───────────────────────────▶│
   │          (握手消息摘要的加密摘要)               │
   │                                               │
   │◀────────── ChangeCipherSpec ─────────────────│
   │◀────────── Finished ─────────────────────────│
   │                                               │
   │══════════ 应用数据加密通信 ════════════════════│

详细步骤解析

  1. ClientHello:客户端发送支持的 TLS 版本、密码套件列表、一个 32 字节随机数(Client Random)

  2. ServerHello:服务器选择密码套件,发送自己的 32 字节随机数(Server Random)

  3. Certificate:服务器发送证书链(Leaf → Intermediate → Root)

  4. ServerKeyExchange(ECDHE 时必需):发送 DH/ECDH 临时公钥参数

  5. CertificateRequest(双向认证时):请求客户端证书

  6. ClientKeyExchange:客户端发送 DH 公钥或加密的预主密钥

  7. Finished:双方基于 master_secret 计算并交换握手消息摘要

密码套件格式TLS_密钥交换__WITH_对称加密_消息认证

例如 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 表示:

  • ECDHE 密钥交换
  • RSA 签名
  • AES-256-GCM 对称加密
  • SHA-384 MAC/哈希

TLS 1.3 握手(1-RTT)

TLS 1.3 大幅简化协议设计,将握手时间缩短至一次往返(1 RTT):

Client                                          Server
   │                                               │
   │────────── ClientHello ────────────────────────▶│
   │          (支持的密码套件、ECDH公钥、0-RTT数据) │
   │                                               │
   │◀──────── ServerHello ─────────────────────────│
   │          (选定的密码套件、ECDH公钥)            │
   │◀──────── {EncryptedExtensions} ──────────────│
   │          (服务器配置参数)                      │
   │◀──────── {Certificate} ──────────────────────│
   │          (服务器证书链)                        │
   │◀──────── {CertificateVerify} ────────────────│
   │          (用服务器私钥签名的摘要)              │
   │◀──────── {Finished} ─────────────────────────│
   │          (握手消息的加密摘要)                  │
   │                                               │
   │══════════ 应用数据加密通信 ════════════════════│

TLS 1.3 的关键改进

特性TLS 1.2TLS 1.3
握手往返2-RTT1-RTT
密钥交换RSA、DH、ECDH(多种)仅 ECDHE(强制前向保密)
0-RTT不支持支持(可选)
静态 RSA/ DH 密钥交换允许移除
RC4、3DES、MD5、SHA-1允许移除
密码套件协商复杂简化为 5 种

证书验证流程

每次 TLS 握手期间,客户端必须完整验证服务器证书:

# OpenSSL 查看证书详细信息
openssl s_client -connect example.com:443 -showcerts
 
# 验证证书链
openssl verify -CAfile root-ca.crt -untrusted intermediate.crt leaf.crt
 
# 检查证书有效期
openssl x509 -in cert.pem -noout -dates
 
# 验证主机名匹配
openssl s_client -connect example.com:443 2>&1 | grep "Subject:"

验证步骤

  1. 链完整性验证:从 Leaf 证书向上追溯,每个证书的签名必须由其父证书的公钥验证通过

  2. 签名验证:检查证书签名算法是否符合安全标准(拒绝 SHA-1、MD5 等)

  3. 有效期验证:当前时间必须在 notBefore 和 notAfter 之间

  4. 主机名验证:证书的 CN/SAN 必须与连接的域名匹配

  5. 吊销状态检查:通过 CRL 或 OCSP 确认证书未被撤销

0-RTT 数据重放攻击

TLS 1.3 支持 0-RTT 恢复模式,客户端可在首次握手中发送加密数据(Early Data):

Client                                          Server
   │                                               │
   │────────── ClientHello ────────────────────────▶│
   │          (PSK 标识、0-RTT 加密数据)            │
   │                                               │
   │◀──────── ServerHello ─────────────────────────│
   │          (接受 0-RTT)                         │
   │◀──────── {Early Data} ───────────────────────│
   │          (解密后的 0-RTT 数据)                │

安全隐患:0-RTT 数据可能被攻击者重放。由于 0-RTT 数据使用 PSK(Pre-Shared Key)加密,而 PSK 可能在多个上下文中相同,存在重放风险。

缓解措施

  • 0-RTT 数据应仅用于幂等操作
  • 服务端实现重放检测机制
  • 使用 anti_replay 窗口限制

证书管理

X.509 证书结构

X.509 v3 证书遵循 ASN.1 DER 编码格式3,核心结构:

Certificate ::= SEQUENCE {
    tbsCertificate       TBSCertificate,      -- 待签名证书内容
    signatureAlgorithm   AlgorithmIdentifier, -- 签名算法
    signatureValue       BIT STRING            -- CA 的签名
}

TBSCertificate ::= SEQUENCE {
    version         [0] EXPLICIT Version DEFAULT v1,  -- 版本号
    serialNumber         CertificateSerialNumber,     -- 序列号
    signature            AlgorithmIdentifier,         -- 签名算法
    issuer               Name,                        -- 颁发者
    validity             Validity,                    -- 有效期
    subject              Name,                        -- 主体
    subjectPublicKeyInfo SubjectPublicKeyInfo,        -- 公钥信息
    ...
}

关键字段说明

字段说明示例
serialNumberCA 分配的唯一序列号04:A2:B3:…
issuer颁发者信息(CA)“C=US, O=Let’s Encrypt”
validity有效期间Not Before: 2024-01-01
subject证书持有者信息”CN=example.com”
subjectPublicKeyInfo公钥及算法RSA 2048-bit / ECDSA P-256

信任链结构

证书链遵循三级分层结构:

                    ┌──────────────────┐
                    │    Root CA       │
                    │  (自签名证书)     │
                    │  通常离线存储     │
                    └────────┬─────────┘
                             │ 自签名
                             ▼
                    ┌──────────────────┐
                    │ Intermediate CA  │  (可能有多个中间 CA)
                    │  (由 Root 签发)   │
                    └────────┬─────────┘
                             │ 签名
                             ▼
                    ┌──────────────────┐
                    │   Leaf Certificate│
                    │  (服务器/客户端证书)│
                    │  由 Intermediate  │
                    │  签发,有效期短    │
                    └──────────────────┘

信任链验证

# 查看完整证书链
openssl s_client -connect www.google.com:443 -showcerts 2>/dev/null | \
  openssl x509 -noout -subject -issuer
 
# 提取证书链并保存
openssl s_client -showcerts -connect example.com:443 </dev/null 2>/dev/null | \
  sed -n '/-----BEGIN/,/-----END/p' > chain.pem

证书吊销机制

CRL(Certificate Revocation List)

CRL 是由 CA 发布的被吊销证书序列号列表:

CertificateRevocationList ::= SEQUENCE {
    tbsCertList       TBSCertList,
    signatureAlgorithm AlgorithmIdentifier,
    signatureValue    BIT STRING
}

TBSCertList ::= SEQUENCE {
    version             Version OPTIONAL,
    issuer              Name,
    thisUpdate          Time,
    nextUpdate          Time OPTIONAL,
    revokedCertificates RevokedCertificates OPTIONAL,
    ...
}

缺点:CRL 可能很大,客户端需要定期下载更新。

OCSP(Online Certificate Status Protocol)

RFC 6960 定义的实时查询协议:

# 使用 OpenSSL 查询 OCSP 状态
openssl ocsp -CAfile chain.pem \
  -issuer intermediate.crt \
  -cert server.crt \
  -url http://ocsp.example.com

响应类型

  • good:证书有效
  • revoked:证书已被吊销
  • unknown:签发 CA 不在响应中

OCSP Stapling

服务器主动获取 OCSP 响应并在 TLS 握手时发送给客户端:

服务器 ──── OCSP Response ──── CA
    │
    │ (服务器定时刷新 OCSP 响应)
    │
    ▼
客户端 ◀─── Certificate + Stapled OCSP Response ◀─── 服务器

优势

  • 客户端无需单独查询 OCSP
  • 减少延迟
  • 保护用户隐私(不暴露访问的网站)

证书有效期趋势

受 CA/Browser Forum 政策推动,证书有效期持续缩短:

年份最大有效期说明
2000s10 年早期标准
20125 年Ballot 89
20182 年Ballot 193
20201 年Ballot SC27
202947 天计划目标(SubCA:397天)4

趋势驱动因素

  • 缩短有效期可限制证书泄露后的影响时间
  • 促进自动化证书管理(ACME 协议)
  • 减少吊销列表大小

mTLS(双向 TLS)

概述

传统 TLS 仅验证服务器身份(单向认证)。mTLS 要求客户端也提供证书,实现双向认证

┌─────────────────────────────────────────────────────────────┐
│                      mTLS 握手流程                          │
├─────────────────────────────────────────────────────────────┤
│  Client ──── ClientHello + 客户端证书 ────▶ Server         │
│            ◀─── ServerHello + 服务器证书 ◀── Server         │
│            ◀─── CertificateRequest ◀── Server               │
│            ◀─── ServerHelloDone ◀── Server                 │
│  Client ──── Certificate + ClientKeyExchange ────▶ Server   │
│  Client ──── CertificateVerify(签名) ────▶ Server          │
│  Client ──── Finished ────▶ Server                          │
│            ◀─── Finished ◀── Server                        │
└─────────────────────────────────────────────────────────────┘

应用场景

mTLS 广泛应用于以下场景:

  1. 零信任架构:每次访问都需要验证设备和服务身份
  2. 服务网格(Service Mesh):如 Istio、Linkerd 中的服务间通信
  3. API 安全性:保护 sensitive API endpoints
  4. IoT 设备认证:设备身份验证
  5. 企业内部网络:替代 VPN 的零信任方案
# 使用 mutual TLS 测试连接
openssl s_client -connect service.mesh.local:8443 \
  -cert client.crt \
  -key client.key \
  -CAfile ca.crt

与单向 TLS 的对比

特性单向 TLSmTLS
服务器证书必须必须
客户端证书可选必须
用户身份验证依赖应用层网络层完成
适用场景公众网站内部服务、企业网络
复杂性高(证书管理)

实际调试

OpenSSL 命令行工具

# 测试 SSL/TLS 连接
openssl s_client -connect example.com:443 -tls1_2
 
# 指定 SNI(Server Name Indication)
openssl s_client -connect example.com:443 -servername api.example.com
 
# 验证证书链完整性
openssl s_client -showcerts -connect mail.google.com:443 </dev/null
 
# 测试 TLS 1.3 支持
openssl s_client -tls1_3 -connect example.com:443
 
# 查看证书的 SAN(Subject Alternative Names)
openssl x509 -in cert.pem -noout -text | grep -A1 "Subject Alternative Name"
 
# 提取公钥指纹
openssl x509 -in cert.pem -noout -fingerprint -sha256
 
# 检查 OCSP Stapling 是否启用
openssl s_client -connect example.com:443 -status </dev/null 2>&1 | grep "OCSP Response"

常见错误诊断

证书过期

SSL alert number 45  # certificate_expired

检查

openssl x509 -in cert.pem -noout -dates
# notBefore=Jan  1 00:00:00 2024 GMT
# notAfter=Jan  1 00:00:00 2025 GMT

证书链不完整

SSL alert number 50  # handshake_failure

解决:确保服务器正确配置了中间证书

# 追加中间证书到服务器配置
cat leaf.crt intermediate.crt > chain.pem

主机名不匹配

SSL alert number 48  # certificate_unknown

检查

openssl s_client -connect 192.168.1.1:443 -servername example.com
# 或查看证书 SAN
openssl x509 -in cert.pem -noout -ext subjectAltName

自签名证书

# 验证自签名证书
openssl verify -CAfile selfsigned.crt selfsigned.crt
# selfsigned.crt: OK (但仅当 CAfile 匹配时)

SSL Labs 测试

SSL Labs Server Test 是最全面的 TLS 配置检测工具:

  • 支持全端口扫描
  • 模拟多种客户端
  • 评级从 A+ 到 F
  • 提供详细的协议/密码套件分析
  • 检测心脏出血、POODLE 等漏洞

优秀配置目标

  • 协议版本:仅 TLS 1.2 和 1.3
  • 密码套件:仅 AEAD 套件(AES-GCM、ChaCha20-Poly1305)
  • 密钥强度:RSA ≥ 2048-bit,ECC ≥ P-256
  • 证书链:完整且无自签中间 CA

性能优化

TLS 终止位置

                    ┌─────────────────────────────────────┐
                    │           客户端                      │
                    └─────────────┬───────────────────────┘
                                  │ HTTPS
                    ┌─────────────▼───────────────────────┐
                    │     负载均衡器 / 边缘节点             │
                    │     (TLS 终止)                      │
                    └─────────────┬───────────────────────┘
                                  │ HTTP(内网)
                    ┌─────────────▼───────────────────────┐
                    │     源站服务器                        │
                    │     (无需处理 TLS)                   │
                    └─────────────────────────────────────┘

优势

  • 减轻源站计算负载
  • 集中管理证书
  • 便于添加 WAF、DDoS 防护
  • 缓存优化(如 HTTP/2)

劣势

  • 内网传输未加密(需额外保护)
  • 额外的网络跳数

会话恢复机制

Session ID 恢复

服务器在内存中存储会话状态,客户端通过 Session ID 恢复:

首次握手:                          恢复握手:
Client ──── ClientHello ────▶       Client ──── ClientHello
         (无 Session ID)                     (Session ID)
         ◀─── ServerHello                    ◀─── ServerHello
         ◀─── ...                           ◀─── (无需完整握手)

Session Ticket 恢复

服务器将加密的会话状态封装为 ticket 发送给客户端:

# Nginx 配置会话票证
ssl_session_tickets on;
ssl_session_ticket_key /etc/nginx/session.key;

硬件加速

  • TLS 加速卡:如 Intel QuickAssist、AMD Seattle
  • 专用 SSL 卸载芯片:降低 CPU 开销
  • AES-NI 指令集:现代 CPU 内置 AES 加速

连接复用统计

# 查看 OpenSSL 连接复用统计
openssl s_client -connect example.com:443 -reconnect </dev/null 2>&1 | \
  grep "Reused\|Reused ("
 
# 输出示例
    Reused: no           (首次连接)
    Reused: yes          (会话恢复)

最佳实践

协议版本配置

Nginx 配置

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256';
ssl_prefer_server_ciphers off;  # 客户端决定最优先算法

Apache 配置

SSLProtocol -all +TLSv1.2 +TLSv1.3
SSLCipherSuite TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
SSLHonorCipherOrder off

密钥算法选择

算法状态建议
RSA 2048-bit安全推荐
RSA 4096-bit安全可选(性能开销大)
ECDSA P-256安全推荐(性能更优)
ECDSA P-384安全可选
RSA 1024-bit不安全禁用
ECDSA P-224不安全禁用

证书申请流程(ACME)

使用 Let’s Encrypt 和 Certbot 实现自动化:

# 安装 Certbot
sudo apt install certbot python3-certbot-nginx
 
# 申请证书(DNS 验证)
sudo certbot certonly --manual --preferred-challenges dns \
  -d example.com -d "*.example.com"
 
# 自动续期
sudo certbot renew --dry-run
 
# Nginx 自动配置
sudo certbot --nginx -d example.com

Nginx 自动配置示例

server {
    listen 443 ssl http2;
    server_name example.com;
 
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    
    # 现代 TLS 配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;
    
    # HSTS (可选)
    add_header Strict-Transport-Security "max-age=63072000" always;
}

监控与告警

关键监控指标:

  • 证书过期时间(建议提前 30 天告警)
  • TLS 版本分布(确保无 TLS 1.0/1.1)
  • 密码套件使用情况
  • 连接错误率
# 检查证书过期时间(Zabbix/Lambda 脚本示例)
#!/bin/bash
CERT="/etc/ssl/certs/server.crt"
EXPIRY=$(openssl x509 -in "$CERT" -noout -enddate | cut -d= -f2)
EPOCH=$(date -d "$EXPIRY" +%s)
NOW=$(date +%s)
DAYS=$(( (EPOCH - NOW) / 86400 ))
 
if [ $DAYS -lt 30 ]; then
    echo "ALERT: Certificate expires in $DAYS days"
fi

相关主题

参考资料

Footnotes

  1. SSL 3.0 被禁止的 RFC:RFC 7568 - Deprecating Secure Sockets Layer Version 3.0

  2. TLS 1.0/1.1 弃用时间线:Chrome、Firefox、Safari 均于 2020 年移除支持

  3. X.509 标准:ITU-T X.509 | ISO/IEC 9594-8 - Information technology - Open Systems Interconnection

  4. CA/Browser Forum Ballot SC-47 和长期证书政策讨论