1. TLS/SSL 协议基础概述

刚入门网络协议栈的时候,我总觉得 TLS 就是给 HTTP 加了一把锁,挺简单的。后来在排查线上“请求超时”问题时,被证书链断裂和密码套件不匹配狠狠上了一课。今天咱们从头捋一遍 TLS/SSL,把那些容易踩坑的点都揪出来。

1.1 什么是 TLS/SSL?

TLS(Transport Layer Security)和 SSL(Secure Sockets Layer)是同一类协议。SSL 是 Netscape 在 90 年代搞出来的,后来 IETF 接手并改名为 TLS。目前市面上说的“SSL 证书”其实大半都是 TLS 证书,只是大家叫习惯了。

它的核心作用就三个:加密通信(防止偷听)、身份验证(防止冒充)、数据完整性(防止篡改)。说白了,就是让你的数据在公网上裸奔时不被人扒光。

实战血泪:我曾经在一个金融项目中遇到“中间人攻击”——因为客户端没校验证书公钥,被伪基站截了流量,亏了客服部的几百张补偿券才摆平。从那以后,我每次上线 HTTPS 都会用 openssl s_client 手动验一遍证书链。

1.2 TLS 协议栈在哪一层?

你想想看,TCP 是四层模型中的传输层,应用层是 HTTP、FTP 这些。TLS 插在中间,像夹心饼干——它依赖 TCP 的可靠传输,但又在应用层之下。

一张图就能说清位置关系:

TLS 协议栈位置与握手流程概览 应用层 HTTP / FTP / SMTP TLS 层 握手 / 记录 / 警报 传输层 TCP 网络层 IP TLS 1.2 握手精简流程 ① ClientHello → 密码套件 + 随机数 ② ServerHello → 选定套件 + 证书 ③ 客户端校验证书 → 预主密钥 ④ ChangeCipherSpec → 加密开始 ⑤ 应用数据加密传输 依赖 TCP 可靠传输

嗯,图上画得很清楚:TLS 层在 TCP 上面,应用层下面。握手阶段交换密码套件和证书,之后才用协商好的对称密钥加密应用数据。

1.3 核心概念速览

我习惯用一张表来记这些易混的东西:

术语一句话解释常见坑
证书服务器的身份证,内含公钥和签名过期、域名 mismatch、自签名不受信任
密码套件密钥交换+认证+加密+MAC 的组合客户端和服务端没交集时握手失败
会话重用复用之前协商的密钥,避免重复握手session cache 失效导致延迟骤增
SNI客户端告诉服务器要访问哪个域名老客户端不支持,多域名 HTTPS 出错

小技巧:排查密码套件不匹配时,用 openssl ciphers -v 列出当前 OpenSSL 支持的全部套件。我曾经在升级 OpenSSL 后忘了同步旧应用,结果所有老客户端都报“no shared cipher”,排查了整整一个下午。

1.4 握手过程核心步骤

TLS 握手其实不复杂,但有几个易混点。以最常用的 TLS 1.2 为例:

  1. ClientHello:客户端说你支持哪些密码套件、TLS 版本、还有个 32 字节随机数。
  2. ServerHello + 证书:服务器选一个套件,发回证书链和自己的随机数。
  3. 证书校验:客户端检查证书链是否完整、是否被信任、域名是否一致。
    ⚠️ 这里最容易出问题:中间证书缺失、根证书过期、OCSP 装订没配好。
  4. 预主密钥:客户端生成一个 48 字节的预主密钥,用服务器公钥加密后发过去。
  5. 主密钥 & 会话密钥:双方根据两个随机数+预主密钥,通过 PRF 伪随机函数算出对称密钥。
  6. ChangeCipherSpec:通知对方后面全用加密通信。
  7. Finished:双方对握手消息做 HMAC 校验,防止被篡改。

避坑指南:我曾经调试过一个问题:客户端一直报“handshake failure”,但证书明明有效。最后抓包发现,服务端要求客户端证书(双向认证),而客户端没发证书。所以,不要默认服务端一定只做单边认证,得看密码套件里的密钥交换算法。

1.5 TLS 版本对比

版本发布年份主要特点现状
SSL 3.01996第一个广泛使用的版本已废弃,POODLE 漏洞
TLS 1.01999基于 SSL 3.0 改进已废弃,BEAST 攻击
TLS 1.12006增加 CBC IV 保护已废弃,PCI DSS 要求禁用
TLS 1.22008当前主力,支持 AEAD 套件广泛使用,推荐启用
TLS 1.32018握手从 2-RTT 降到 1-RTT,移除不安全套件性能更好,逐步普及

我个人建议:新服务直接开 TLS 1.2 和 1.3,关掉 1.0/1.1。如果客户有老设备,至少也得保留 1.2 作为底线。有一次我因为没关 1.0,被安全扫描扫出漏洞,连夜改 Nginx 配置……

1.6 密码套件到底是个啥?

你看到过类似 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 这种长字符串吗?拆开看就四个部分:

  • 密钥交换:ECDHE(临时椭圆曲线 DH)、RSA 等。ECDHE 支持前向安全,建议优先选。
  • 认证:RSA、ECDSA。RSA 证书最通用,ECDSA 证书密钥更小。
  • 加密:AES_256_GCM、CHACHA20_POLY1305 等。GCM 是 AEAD 模式,推荐。
  • MAC/PRF:SHA384、SHA256。用于导出密钥和完整性校验。

实战经验:我见过一台老旧服务器只支持 RSA 密钥交换,但压力大了之后 RSA 解密性能跟不上,导致 CPU 跑满。后来换成 ECDHE + ECDSA,性能提升 30%。所以选套件不只是安全,还得考虑硬件。

1.7 证书链的常见问题

证书链就是从服务器证书一直追溯到根证书。中间证书如果没配全,或者根证书过期,客户端就会报错。我记得有一次排查“证书不可信”问题,发现是运维只配了服务器证书,没配中间证书。浏览器自动补全了一些根,但手机 App 用的系统 CA 不全,直接就挂了。

检查命令:

openssl s_client -connect example.com:443 -showcerts
# 观察返回的证书数量与顺序
# 正常应该是:服务器证书 → 中间证书 → 根(可选)

如果发现少了一张中间证书,让运维把中间证书放到服务器证书后面(Nginx 的 ssl_certificate 文件里按顺序拼接)。

1.8 总结要点

  • TLS 是加密协议,位于传输层与应用层之间。
  • 握手最慢(2-RTT),重用会话可以减少延迟。
  • 证书链必须完整、有效、域名匹配。
  • 密码套件要选择前向安全的 ECDHE + AEAD 加密。
  • 版本越低漏洞越多,尽快迁移到 TLS 1.2+。