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 握手四步走

  1. Client Hello:客户端告诉服务器「我支持 TLS 1.3、AES-GCM、X25519……」,还带一个随机数。
  2. Server Hello + 证书:服务器选好参数,发回证书(内含公钥)和另一个随机数。
  3. 密钥交换:客户端验证证书没问题,生成「预主密钥」,用服务器公钥加密发过去。服务器用私钥解密得到预主密钥。
  4. 会话密钥就绪:双方用两个随机数 + 预主密钥算出相同的对称密钥。之后所有 HTTP 数据都用这个密钥加密。

第二步里证书验证是关键。我见过有人自签名证书跳过验证,结果被中间人攻击,数据库被拖走。千万不要省这一步。

曾经有个用户在生产环境配了自签名证书,还把客户端验证关掉了。攻击者在同一内网做了 ARP 欺骗,轻松劫持了所有加密流量。嗯,那个 case 最后上了安全事件复盘会。

3.2 握手中的密码学工具箱

我把握手用到的技术拆成一张表,你对照着看更清楚。

阶段 使用的技术 作用
Client Hello 随机数生成 防止重放攻击
Server Hello + 证书 非对称加密 + 数字签名 身份认证 + 公钥分发
证书验证 CA 证书链校验 + 签名验证 确认服务器身份可信
密钥交换 非对称加密(RSA/ECDHE) 安全传输预主密钥
会话密钥生成 HMAC + 伪随机函数 派生出对称加密密钥
TLS 握手流程 TLS 1.3 握手核心流程 客户端 (Client) 服务器 (Server) ① Client Hello ② Server Hello + 证书 ③ 验证证书 ④ 生成预主密钥 + 加密 ⑤ 私钥解密 → 预主密钥 (只有服务器能解开) ⑥ 双方生成对称会话密钥 支持的版本 / 密码套件 证书 + 公钥 + 签名 用公钥加密的预主密钥 两端各自派生会话密钥 握手完成后,所有 HTTP 数据使用 AES-GCM 对称加密传输

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 握手的本质就是用非对称加密安全传递一个临时密钥,后续用对称加密提速。我在不同项目里反复看到,只要把证书链配全、密码套件选对、时钟校准好,握手基本不会出问题。