2. TLS/SSL 协议简介

说到证书管理,TLS/SSL 协议是绕不过去的核心基础。说白了,它就是互联网上最常用的加密通道——你每次打开 HTTPS 网站、发支付请求、连 VPN,背后都是它在干活。我做了这么多年证书自动化,每次遇到问题查到最后,十有八九还是跟握手的某个细节有关。这一节咱们就把它扒开看看实际是怎么跑的。

2.1 它到底解决了什么问题?

在没有 TLS 的年代,你给服务器发一条消息,经过的每个路由器都能看到明文。密码、令牌、信用卡号,全都裸奔。TLS 的目标很简单:给这条通道上三把锁。

  • 机密性:消息只有两端能看懂,中间人拿到的全是乱码。
  • 完整性:数据在传输中被改了接收方立刻能发现,就像快递箱子上贴了防拆封条。
  • 身份验证:你连接的真的是你要找的服务器,而不是某个冒牌货——证书就是干这件事的。

我刚开始做证书管理时,总觉得机密性最重要。后来在生产环境踩过一个坑——某个中间设备偷偷修改了 HTTP 响应注入广告,但因为 TLS 完整性校验没打开,客户端根本没发现。嗯,从那以后我每次配置都会把完整性校验单独写进检查清单。

2.2 协议栈长什么样?

TLS 协议本身分两层。上层是握手协议、警报协议、变更密码规范协议——这些管的是“怎么安全地建立链接”。下层是记录协议——它管的是“怎么把加密后的数据打包发送”。你可以把上层想象成两个人见面先交换证件、商定暗号,下层就是他们用暗号写好信的邮递员。

一个小印象:TLS 1.3 相比 1.2 少了一次往返,握手从 2-RTT 降到了 1-RTT,还顺便砍掉了很多不安全的加密套件。我自己的项目里,从 1.2 升级到 1.3 后,首次页面加载时间优化了大约 15%。

2.3 握手过程——核心流程

握手是 TLS 最复杂也最关键的部分。我习惯把它拆成三个大步骤:

  1. 握手开始 + 协商:客户端发 ClientHello(带上支持的 TLS 版本、加密套件列表),服务器回 ServerHello(选定版本和套件)。
  2. 证书 + 密钥交换:服务器把证书链发给客户端。客户端验证证书(后几章细讲),然后双方用非对称加密协商出一个临时对称密钥。
  3. 握手结束 + 安全通道建立:双方互相发送 Finished 消息确认,之后所有数据都走对称加密。

为了让你直观看到信息流向,我画了一张简化的流程图(只展示了最常见的单向认证场景)。

TLS 1.3 简化握手流程 客户端 服务器 ClientHello ServerHello + Certificate + KeyShare 验证证书链 Client Finished Server Finished 安全通道建立(对称加密) 应用数据(加密) 应用数据(加密) 注:本图展示 TLS 1.3 单向认证场景,实际握手还包括密钥派生、HelloRetryRequest 等细节

你想想看,这里头的密钥交换用了非对称加密,但后面的传输用的都是对称加密——为什么要这么折腾?因为非对称加密慢,对称加密快。只拿非对称加密保护一次握手,然后双方用协商出来的对称密钥快速传输海量数据。我在做一个高并发 API 网关时,发现每次握手如果都用 RSA 2048 位做解密,服务器 CPU 瞬间飙到 90%,换成 ECDSA 证书后负载降到 30%。所以现在新项目我一般都会优先推荐 ECDSA。

2.4 证书在握手里的角色

证书是服务器(也可能客户端)的身份证明。握手第二步,服务器把证书发过来,客户端必须做这几件事:

检查项说明我踩过的坑
颁发者可信证书链的根证书必须在信任库中某个内部 CA 根证书忘了装,服务直接挂了
域名匹配证书 CN/SAN 必须与访问域名一致CDN 后端回源域名配了泛域但 SAN 漏了,404
有效期当前时间在 notBefore 和 notAfter 之间监控脚本没检查时区,凌晨 3 点批量过期…
吊销状态OCSP Stapling 或 CRL 确认未吊销曾经忘记配 OCSP 响应缓存,握手慢了好几秒

警报:证书链中间证书缺失是最隐蔽的错误之一。客户端只拿了服务器发的证书,如果中间证书没跟在后面而客户端又没有,握手会直接失败。我建议你在部署后一定用 openssl s_client 模拟一次完整握手验证。

2.5 常见误区与避坑指南

  • 误区一:TLS 可以保护 UDP? 原生不行,但 DTLS 可以。我在物联网项目里用过 DTLS 1.2,跟 TLS 握手几乎一样。
  • 误区二:证书到期前自动续签就万事大吉? 如果客户端 OCSP 缓存了旧证书的公钥或者证书链变过,还是会有问题。我建议每次新证书替换后清一遍 CDN 缓存。
  • 误区三:握手慢就是网络问题? 不一定。记得有一次半夜告警说 HTTPS 超时,我查出来是服务器硬件熵池耗尽导致 ECDHE 密钥生成阻塞,加了个硬件随机数生成器就解决了。

我个人习惯在项目里用这条命令验证证书和握手:
openssl s_client -connect example.com:443 -tlsextdebug -status
输出里会显示证书链是否完整、OCSP 状态、选择的加密套件。如果是线上环境,我会加个 -servername 确保 SNI 正确。

2.6 小结

TLS/SSL 协议是整个证书体系的运行环境。你掌握了握手过程,就知道证书到底在什么时候被谁验证,也知道密钥是怎么协商出来的。有了这个基础,后面我们再聊证书生命周期管理、自动化签发、轮换策略,你就能理解为什么每一步那么设计。嗯,别急,后面会越来越实用。