"为什么 TLS,在 HTTP 之上加一层 TLS 加密,防止中间人窃听和篡改。">HTTPS 比 HTTP 安全?""TLS 握手到底在做什么?""TLS 1.3 比 1.2 快在哪?" —— TLS 是当代互联网的基石,但大多数工程师对它的认识停留在"加个证书就行"。这篇文章把 TLS 握手讲透,涵盖密钥交换、证书验证、性能优化、生产配置。
TLS 解决什么
HTTP 在明文 TCP 上跑,中间任何节点(路由器、WiFi、ISP、运营商)都能看到、改、伪造你的内容。TLS 在 TCP 和 HTTP 之间加一层,提供:
- 机密性:加密,中间人看不到内容。
- 完整性:消息认证码(MAC),中间改了能发现。
- 身份验证:证书,确认你连的是真服务器(不是钓鱼网站)。
TLS 1.2 握手流程
客户端 (C) 服务端 (S)
| |
| --- ClientHello ----------> | // 1. 客户端发起
| 支持的 TLS 版本 |
| 支持的加密套件列表 |
| 随机数 client_random |
| SNI (Server Name) |
| |
| <-- ServerHello ------------ | // 2. 服务端响应
| 选定的 TLS 版本 |
| 选定的加密套件 |
| 随机数 server_random |
| |
| <-- Certificate ----------- | // 3. 服务端发证书
| 证书链(server + CA) |
| |
| <-- ServerKeyExchange ----- | // 4. 服务端发 DH 参数
| (ECDHE 时) |
| |
| <-- ServerHelloDone ------- |
| |
| --- ClientKeyExchange ---->| // 5. 客户端发自己 DH 参数
| |
| --- ChangeCipherSpec ---->| // 6. 客户端切换到加密
| --- Finished ------------>| // 用握手数据 hash 验证
| |
| <-- ChangeCipherSpec ----- |
| <-- Finished ------------- |
| |
| === 加密应用数据 ========== |
2 个 RTT(往返时延)才能开始传应用数据。在跨大洋场景下,延迟可达几百 ms。
关键步骤详解
1. 加密套件协商
ClientHello 里 cipher_suites 列出支持的算法组合,如:
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
分解:
ECDHE 密钥交换(椭圆曲线 DH)
RSA 身份认证(用 RSA 证书)
AES_128_GCM 对称加密(AES 128 位 GCM 模式)
SHA256 完整性算法
# 服务端从客户端列表里挑一个支持的
2. 证书验证
客户端拿到服务端证书后:
- 验证签名链:服务证书 → 中间 CA → 根 CA(根 CA 在操作系统 / 浏览器的信任库里)。
- 验证有效期:不能过期,不能未生效。
- 验证域名:证书的 CN / SAN 字段必须包含你访问的域名。
- 验证撤销:CRL(证书撤销列表)或 OCSP(在线证书状态协议)查证书有没有被吊销。
任何一步失败,浏览器报"不安全"或拒绝连接。这就是为什么自签证书会被警告 —— 没有受信 CA 签发。
3. 密钥交换(ECDHE)
双方用 ECDH(椭圆曲线 Diffie-Hellman)算法协商出一个共享密钥,这个密钥不通过网络传输!即使中间人录下全部握手,也算不出共享密钥。
ECDHE 的 E 表示 Ephemeral(临时)—— 每次握手用新的 DH 密钥对,提供"前向安全性"(Forward Secrecy):服务器私钥泄漏后,过去录下的 TLS 通信也不能解密。
TLS 1.3:握手优化
TLS 1.3(2018 RFC 8446)的核心改进:
- 1-RTT 握手:客户端在 ClientHello 就把 key_share(DH 参数)发出去,服务端一次响应就完成密钥协商。
- 0-RTT(可选):之前连过的会话,可以"同时发应用数据和握手",理论上 0-RTT 启动。代价是有重放风险,需要业务幂等。
- 砍掉不安全算法:RC4、SHA1、CBC 模式、RSA 静态密钥交换全部移除。
- 加密握手内容:Certificate 等敏感信息也加密传,不像 1.2 是明文。
TLS 1.3 握手:
--- ClientHello + key_share ----->
<-- ServerHello + key_share + 加密的 {Certificate, Finished}
--- Finished --------------------->
=== 加密应用数据 ===
# 1 RTT 就能开始,比 1.2 少一半
2025 年 TLS 1.3 已经是主流,所有现代浏览器和服务器都支持。新部署默认 1.3。
SNI:同 IP 多域名
一台服务器一个 IP,但有 N 个 HTTPS 域名,怎么知道用哪个证书?Server Name Indication(SNI)—— 客户端在 ClientHello 里告诉服务端"我要访问 example.com",服务端选对应证书。
SNI 是明文的(不加密),所以中间人能看到你在访问哪个域名(虽然看不到具体内容)。Encrypted SNI(ESNI / ECH)是为了加密这个字段的进化版,2025 年仍在逐步部署。
证书类型
- DV(Domain Validated):只验证你拥有域名(通过 DNS 记录或文件)。Let's Encrypt 免费 DV 证书,2 分钟签发。
- OV(Organization Validated):额外验证组织信息。
- EV(Extended Validation):严格的组织身份审核。早期浏览器会显示绿色公司名 —— 现在 UI 简化,EV 优势没了。
- 通配符证书:*.example.com,覆盖所有一级子域名。
Let's Encrypt 实战
# 用 certbot 自动签发并续期
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
# 自动续期(证书 90 天有效期)
sudo systemctl enable --now certbot.timer
# 每天检查,有过期的自动续
Let's Encrypt 已经签发了几十亿张证书,让"HTTPS 普及"成为现实。新项目直接用,没有理由继续用 HTTP。
nginx 的 TLS 配置最佳实践
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;
# 协议:只支持 1.2 和 1.3
ssl_protocols TLSv1.2 TLSv1.3;
# 加密套件:用 Mozilla 推荐(intermediate 兼容性好)
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:...;
ssl_prefer_server_ciphers off;
# OCSP Stapling:服务端帮客户端查证书状态,减少 1 次 OCSP 往返
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 valid=60s;
# HSTS:告诉浏览器"只能 HTTPS 访问我"
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# session cache:重连时复用
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off; # tickets 影响前向安全性,关掉
}
测试 TLS 配置
- SSL Labs:
ssllabs.com/ssltest/,在线打分,A+ 是优秀。 - testssl.sh:命令行工具,详细报告。
- openssl s_client:基础调试:
openssl s_client -connect example.com:443。
常见问题
问题 1:证书过期。线上事故的常见来源。必须监控所有域名证书到期时间,提前 30 天告警。Let's Encrypt 配 certbot 自动续期是最佳实践。
问题 2:中间证书缺失。只提供服务器证书,没有中间 CA 证书。浏览器找不到信任链,报错。务必提供 fullchain.pem(包含中间证书)。
问题 3:私钥泄漏。私钥要权限 600,只有部署进程能读。绝不进 git。泄漏立刻吊销证书 + 重新签发。
问题 4:HTTPS 还能被劫持吗? 能,如果攻击者能往用户操作系统装根证书(企业 MITM 代理常这么做)。所以越来越多 App 用 certificate pinning(代码里写死信任的证书指纹),防止意外信任的根 CA 篡改。
HTTPS 性能
"HTTPS 慢"是 10 年前的认知。现代:
- TLS 1.3 1-RTT,延迟比 HTTP 多 1-2 ms(本地网络)、几十 ms(跨大洋)。
- AES-NI 硬件加速,加密 CPU 开销几乎可忽略。
- HTTP/2 + HTTPS 反而比 HTTP/1.1 快(多路复用、头压缩)。
性能不再是 HTTPS 的瓶颈。所有公网服务必须 HTTPS,这是 2025 年的基础线。
HTTP/3 与 QUIC
HTTP/3 把传输层从 TCP 换成 UDP 上的 QUIC 协议,集成了 TLS 1.3。优势:
- 0-RTT 连接重连:之前连过的服务,新连接立刻发数据。
- 消除队头阻塞:TCP 的丢包会卡所有流,QUIC 每个流独立。
- 连接迁移:从 WiFi 切到 4G 不需要重连。
2025 年主流浏览器都支持 HTTP/3,Cloudflare / Google 等大厂已默认启用。nginx 1.25+ 也支持。
TLS 调优常用参数
# 用 cloudflare 推荐配置,平衡安全性和兼容性
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:...;
ssl_prefer_server_ciphers off;
ssl_dhparam /etc/ssl/dhparam.pem; # 4096 位 DH 参数,提升安全
# 启用 0-RTT(TLS 1.3)
ssl_early_data on;
proxy_set_header Early-Data $ssl_early_data;
# 业务层判断 Early-Data,只允许幂等请求
常见故障
- "NET::ERR_CERT_AUTHORITY_INVALID":中间证书没装。fullchain.pem 要包含完整链。
- "ERR_CERT_DATE_INVALID":证书过期。监控 + 自动续期。
- "SSL_ERROR_RX_RECORD_TOO_LONG":配置错误,某些场景是 HTTP 在 443 端口。
- 客户端时钟错误:服务端没问题,但用户机器时间错了导致证书验证失败。无法控制,只能让用户调时间。
写在最后
TLS 是底层基础设施,大多数工程师不需要深入实现,但要理解它的工作机制 —— 这样配置错了能立刻识别,性能不达标能针对优化。把 TLS 当黑盒会写出不安全或慢的服务。理解握手、证书链、密码套件这三件事,你就能 review 任何 TLS 配置并指出问题。
一图看懂
TLS 1.3 握手一图看懂:
—— 别看了 · 2026