SSL/TLS 协议详解:握手过程、对称加密与非对称加密
加密是 HTTPS 的根基。但很多人一开始就把「对称加密」「非对称加密」「TLS 握手」搅成一锅粥。我刚入行时也这样——折腾了三天没调通证书,最后发现是握手阶段密钥套件没对上。
这一章我们把这三块彻底掰开揉碎。你弄懂了它们,后面的代码配置就是走流程了。
1. 对称加密:快,但有个致命问题
对称加密特别直接。发送方和接收方用同一个密钥,加密和解密都是它。就像你和室友共用一把大门钥匙,谁都能锁门开门。
核心特点
- 速度极快。硬件级优化后,AES-256 加解密 1GB 数据只需几秒。
- 密钥长度短。128 位或 256 位,暴力破解基本不可能。
- 致命短板:密钥怎么安全地给对方?如果你把钥匙寄快递,半路被人复制了怎么办?
我在项目中遇到过客户直接用对称加密做 API 签名,密钥写死在客户端 App 里。反编译一下就全暴露了。嗯,那周我们紧急发版了三次。
常见的对称算法有 AES、ChaCha20、SM4(国密)。目前推荐 AES-256-GCM,自带认证加密,能防篡改。
2. 非对称加密:慢,但解决了分发难题
非对称加密用一对密钥:公钥公开,私钥自己藏好。公钥加密的数据只有私钥能解,反过来私钥签名可以用公钥验证。
你想想看,这就像路边放了个带锁的信箱,谁都可以往里投信(公钥加密),但只有你有钥匙取信(私钥解密)。
| 对比项 | 对称加密 | 非对称加密 |
|---|---|---|
| 密钥数量 | 1 个(双方共享) | 2 个(公钥 + 私钥) |
| 速度 | 快(硬件加速后 1GB/s+) | 慢(RSA 2048 约 1000 次/秒) |
| 典型算法 | AES, ChaCha20, SM4 | RSA, ECDSA, SM2 |
| 主要风险 | 密钥分发被窃听 | 私钥泄露 / 量子计算威胁 |
| HTTPS 中的角色 | 加密实际传输数据 | 握手阶段交换密钥 + 身份认证 |
为什么 HTTPS 不只用非对称加密?因为太慢了。RSA 每秒只能做几百次解密,传个大文件会卡死。所以 TLS 用了「混合加密」——用非对称加密安全地交换一个临时对称密钥,后续数据全走对称加密。
3. TLS 握手:混合加密的现场直播
TLS 握手就是客户端和服务器商量「我们怎么加密聊天」的过程。它发生在 TCP 建立之后,HTTP 数据发送之前。
我第一次用 Wireshark 抓握手包时,看到十几个来回直接懵了。其实核心就 4 个步骤。
3.1 握手四步走
- Client Hello:客户端告诉服务器「我支持 TLS 1.3、AES-GCM、X25519……」,还带一个随机数。
- Server Hello + 证书:服务器选好参数,发回证书(内含公钥)和另一个随机数。
- 密钥交换:客户端验证证书没问题,生成「预主密钥」,用服务器公钥加密发过去。服务器用私钥解密得到预主密钥。
- 会话密钥就绪:双方用两个随机数 + 预主密钥算出相同的对称密钥。之后所有 HTTP 数据都用这个密钥加密。
第二步里证书验证是关键。我见过有人自签名证书跳过验证,结果被中间人攻击,数据库被拖走。千万不要省这一步。
曾经有个用户在生产环境配了自签名证书,还把客户端验证关掉了。攻击者在同一内网做了 ARP 欺骗,轻松劫持了所有加密流量。嗯,那个 case 最后上了安全事件复盘会。
3.2 握手中的密码学工具箱
我把握手用到的技术拆成一张表,你对照着看更清楚。
| 阶段 | 使用的技术 | 作用 |
|---|---|---|
| Client Hello | 随机数生成 | 防止重放攻击 |
| Server Hello + 证书 | 非对称加密 + 数字签名 | 身份认证 + 公钥分发 |
| 证书验证 | CA 证书链校验 + 签名验证 | 确认服务器身份可信 |
| 密钥交换 | 非对称加密(RSA/ECDHE) | 安全传输预主密钥 |
| 会话密钥生成 | HMAC + 伪随机函数 | 派生出对称加密密钥 |
4. 实战避坑:握手失败常见原因
我调试过的握手问题少说也有几十个。大部分坑集中在下面几类。
- 证书链不完整:服务器只发了终端证书,没发中间 CA 证书。客户端不认识签发者,直接拒绝握手。我以前在 Nginx 里漏配过
ssl_trusted_certificate,排查了整整半天。 - 密码套件不匹配:客户端只支持 ECDHE,服务器只配了 RSA。两边谈不拢,握手失败。建议服务端至少开放 5-8 个主流套件。
- 时钟不同步:证书有有效期。客户端时间超前或滞后,会认为证书已过期或尚未生效。我见过一台服务器电池没电导致时间重置到 1970 年,所有 HTTPS 都挂了。
- SNI 缺失:一台服务器部署了多个域名,客户端没发 SNI 扩展,服务器不知道返回哪个证书。现在主流浏览器都带 SNI,但老旧 SDK 可能没有。
快速验证命令:用 openssl s_client -connect example.com:443 -tls1_3 可以看完整握手日志。如果卡在某一步,错误信息会直接告诉你原因。
5. 总结一句话
TLS 握手的本质就是用非对称加密安全传递一个临时密钥,后续用对称加密提速。我在不同项目里反复看到,只要把证书链配全、密码套件选对、时钟校准好,握手基本不会出问题。