入门基础
TLS 工作原理:加密、完整性与身份认证一次讲清
TLS(传输层安全协议)就是让 HTTP 变成 HTTPS 的那一层。它只在开头很短的握手里用一次公钥密码:验证服务器身份、协商出一组全新的会话密钥;之后所有数据都用快速的对称算法加密并校验。结果是:中间人看不懂内容、改不了数据,没有该域名的证书就冒充不了服务器。
TLS 到底保护了什么
TLS 提供三项保证:机密性、完整性和身份认证,三者分别靠不同的机制实现。
| 保证 | 含义 | TLS 1.3 中的实现 | 防住的攻击 |
|---|---|---|---|
| 机密性 | 只有通信双方能读懂数据 | AEAD 加密(AES-GCM、ChaCha20-Poly1305),密钥来自临时密钥交换 | 公共 Wi-Fi、运营商、骨干网上的被动监听 |
| 完整性 | 数据被改动一定会被发现 | 每条记录带认证标签,序号参与 nonce | 运营商插广告、注入脚本、重排或重放记录 |
| 身份认证 | 你连的确实是 example.com |
证书链 + 服务器对握手内容的签名(CertificateVerify) | 伪造服务器的中间人攻击 |
身份认证通常是单向的:服务器出示证书,客户端在 TLS 层保持匿名,之后再用密码或 Token 登录。双方都出示证书的叫双向 TLS,见双向 TLS。
TLS 不负责隐藏一切。服务器 IP、流量大小和时序、以及大多数情况下的域名(通过 DNS 和 SNI 字段)对网络仍然可见。TLS 也不担保网站本身是好是坏:DV 证书只证明申请人在签发那一刻控制着这个域名(见 DV、OV、EV 的区别)。
两类密码学分工合作
TLS 把慢而灵活的非对称密码用在建立连接上,把快的对称密码用在传数据上,两者缺一不可。
| 非对称(公钥)密码 | 对称密码 | |
|---|---|---|
| TLS 里的例子 | ECDHE(X25519、P-256)、混合算法里的 ML-KEM、RSA/ECDSA 签名 | AES-128-GCM、AES-256-GCM、ChaCha20-Poly1305 |
| 密钥形式 | 公钥 + 私钥一对 | 每个方向一把共享密钥 |
| 速度 | 每秒几千次运算 | 有硬件加速时每秒数 GB |
| 在 TLS 中的任务 | 协商密钥、证明身份 | 加密并认证每条记录 |
握手中跑的是临时 Diffie-Hellman 交换:双方各自生成一次性的密钥对,把公钥发给对方,再用自己的私钥和对方的公钥算出同一个共享秘密。窃听者能看到两个公钥,却算不出这个秘密。由于这对临时密钥用完即丢,哪怕日后服务器的证书私钥泄露,也解不开之前录下的流量,这就是前向保密。TLS 1.3 的完整握手强制具备前向保密。
共享秘密不会直接拿来加密,而是先经过 HKDF 密钥派生,为每个方向、每个阶段分别生成密钥和 IV。之后所有数据都用 AEAD 算法保护,加密和认证一步完成。
2024 年 11 月起(Chrome 131),Chrome 默认使用混合密钥交换 X25519MLKEM768,把经典的 X25519 和后量子算法 ML-KEM-768 叠在一起;2025 年 4 月发布的 OpenSSL 3.5 也默认启用。这样即使将来量子计算机攻破 X25519,今天录下的流量依旧安全,详见后量子 TLS。360、QQ 等国内主流浏览器基于 Chromium 内核,行为通常跟随对应版本的 Chrome。
证书在哪里起作用
光有密钥交换,还不知道“跟谁”交换了密钥。中间人完全可以分别和你、和真服务器各做一次密钥交换。证书就是用来解决这个问题的。
TLS 服务器证书是一份 X.509 文档,把一个公钥和一个或多个域名(写在 SAN 扩展里)绑定在一起,并由证书颁发机构(CA)签名。握手时客户端会:
- 收到服务器证书和中间证书;
- 从服务器证书一路向上构建证书链,直到操作系统或浏览器信任库里的某个根证书;
- 检查访问的域名是否在 SAN 里、当前时间是否在有效期内、密钥用途是否允许 TLS 服务器认证,并视客户端而定检查吊销状态和证书透明度证明;
- 验证服务器用私钥对握手记录所做的 CertificateVerify 签名。只有持有私钥的人才签得出来,所以单纯复制一份证书毫无用处。
任何一步失败,浏览器就会弹出 NET::ERR_CERT_AUTHORITY_INVALID、NET::ERR_CERT_COMMON_NAME_INVALID 之类的拦截页。证书链的细节见证书链。
用一段话讲完握手
TLS 1.3 里,客户端先发 ClientHello,里面已经带好了它猜服务器会选的密钥交换公钥(key share),以及支持的密码套件、签名算法、要访问的域名(SNI)和应用层协议(ALPN)。服务器回 ServerHello,附上自己的 key share。此时双方都能算出握手密钥,于是之后的 EncryptedExtensions、Certificate 证书链、CertificateVerify 和 Finished 全部加密传输。客户端验证证书和签名,发出自己的 Finished,紧接着就可以发应用数据。整个过程只要 1 个往返,每条消息的细节见 TLS 握手详解。
记录层:数据实际怎么传
握手之后,所有数据都装在一条条 TLS 记录里传输,每条最多 16KB 明文。记录由 5 字节头部、加密后的内容和认证标签组成:
+--------+---------+---------+------------------------------------+-----------+
| 类型 | 版本 | 长度 | 加密内容 | 认证标签 |
| 1 字节 | 2 字节 | 2 字节 | (数据 + 真实类型 + 可选填充) | 16 字节 |
+--------+---------+---------+------------------------------------+-----------+
0x17 0x0303 <= 2^14+256
(TLS 1.3 里外层类型永远是 application_data)
实际运维中值得知道的几点:
- 大小:每条记录明文上限 2^14 = 16384 字节,大的 HTTP 响应会被切成很多条记录。
- nonce:AEAD 的 nonce 由每个方向的 IV 与 64 位记录序号异或得到。记录被丢弃、重排或重放,下一次标签校验就会失败。
- 隐藏真实类型:TLS 1.3 外层类型统一写成
application_data(23),真实类型(握手、告警还是数据)藏在密文里,还可以加填充掩盖长度。 - 告警:出错时发送告警记录,例如
handshake_failure、bad_certificate;正常关闭发送close_notify,接收方据此判断响应是完整的还是被截断了。
TLS 需要一条可靠的字节流,通常就是 TCP。基于 UDP 的版本叫 DTLS,QUIC 则走了另一条路,下面会讲。
一次 HTTPS 请求的完整过程
首次访问 https://example.com/(HTTP/1.1 或 HTTP/2,TLS 1.3)的时序如下:
浏览器 example.com (203.0.113.10)
| DNS 查询 example.com 的 A/AAAA/HTTPS 记录 ---> 解析器 |
| <--- 203.0.113.10 |
| |
| TCP SYN ------------------------------------------------->| 第 1 个往返
| <------------------------------------------------- SYN-ACK | (TCP)
| ACK + TLS ClientHello(key_share、SNI、ALPN h2)---------->|
| | 第 2 个往返
| <---- ServerHello + {EncryptedExtensions, Certificate, | (TLS)
| CertificateVerify, Finished} |
| 校验证书链、域名、签名 |
| {Finished} + [HTTP GET /] -------------------------------->|
| <-------------------------------------- [HTTP 200 + 正文] | 第 3 个往返
| |
{ } = 握手密钥加密 [ ] = 应用数据密钥加密
也就是说,冷启动时不算 DNS,要 3 个往返才能收到响应的第一个字节;TLS 1.2 的完整握手多 1 个往返。TLS 1.3 恢复会话时可以用 0-RTT 把请求塞进第一个包里,代价是存在重放风险(见 TLS 1.3)。
国内很多站点前面挂着阿里云、腾讯云的负载均衡或 CDN,这时浏览器的 TLS 握手是和云厂商的边缘节点完成的,协议版本、套件由云控制台里的 TLS 策略决定,源站上的 Nginx 配置只影响“边缘到源站”这一段。
TLS 与 HTTP/2、HTTP/3 的关系
各个 HTTP 版本都建立在 TLS 之上,只是用法不同。
| HTTP/1.1 | HTTP/2 | HTTP/3 | |
|---|---|---|---|
| 传输层 | TCP | TCP | 基于 UDP 的 QUIC |
| 安全层 | TLS 1.2 或 1.3 | TLS 1.2 及以上(浏览器只支持加密的 HTTP/2) | QUIC 内嵌 TLS 1.3 握手 |
| 协商方式 | ALPN http/1.1 或不协商 |
ALPN h2 |
ALPN h3,通过 Alt-Svc 头或 HTTPS DNS 记录发现 |
| 数据封装 | TLS 记录 | TLS 记录 | QUIC 包保护,没有 TLS 记录 |
| 新连接发出请求前的往返数 | 2(TLS 1.3) | 2(TLS 1.3) | 1 |
HTTP/1.1 和 HTTP/2 之间的选择就发生在 TLS 握手里:客户端通过 ALPN 报出 h2,http/1.1,服务器在 EncryptedExtensions 里选定一个。RFC 9113 还要求 HTTP/2 在 TLS 1.2 下禁用一大批弱套件。
HTTP/3 的做法不一样:QUIC 把 TLS 1.3 的握手消息放进自己的 CRYPTO 帧里,用 TLS 派生的密钥保护 QUIC 数据包,传输层握手和加密握手合并成 1 个往返完成。QUIC 离不开 TLS 1.3,所以不存在明文的 HTTP/3。
TLS 版本一览
公网服务器只应开启 TLS 1.2 和 TLS 1.3。
| 版本 | 年份 | 规范 | 现状 |
|---|---|---|---|
| SSL 2.0 | 1995 | (Netscape) | RFC 6176 禁用 |
| SSL 3.0 | 1996 | RFC 6101(历史文档) | RFC 7568 废弃(POODLE) |
| TLS 1.0 | 1999 | RFC 2246 | RFC 8996 废弃(2021 年 3 月) |
| TLS 1.1 | 2006 | RFC 4346 | RFC 8996 废弃 |
| TLS 1.2 | 2008 | RFC 5246(已被 RFC 9846 取代,要求并入其中) | 仍在使用,配合 ECDHE + AEAD 套件是安全的 |
| TLS 1.3 | 2018 | RFC 8446,2026 年 7 月修订为 RFC 9846 | 当前版本,优先使用 |
主流浏览器在 2020 年前后都移除了 TLS 1.0/1.1。关掉旧版本后如果老客户端连不上,浏览器一般报 ERR_SSL_VERSION_OR_CIPHER_MISMATCH。
2026 年 7 月 IETF 发布了 RFC 9846,这是 TLS 1.3 的一次小修订:版本号仍是 0x0304,和现有实现向后兼容,主要是把含糊的条文写清楚,并收紧少数要求,例如禁止在不同连接之间复用 key share、禁止协商 TLS 1.0/1.1。它同时取代了 RFC 5246,TLS 1.2 的实现要求也一并写进了这份文档。
另外,国内还有一套基于国密算法的体系:RFC 8998 为 TLS 1.3 定义了 SM4/SM3 套件,政务、金融等场景还会用到国家标准的 TLCP 协议(签名证书 + 加密证书的双证书体系)。这类连接需要支持国密的浏览器或客户端,普通 Chrome 并不支持。
自己动手看一看
openssl s_client 会在终端里完成一次真实握手,并打印协商结果:
openssl s_client -connect example.com:443 -servername example.com -brief </dev/null
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Peer certificate: CN=example.com
Hash used: SHA256
Signature type: ecdsa_secp256r1_sha256
Verification: OK
Negotiated TLS1.3 group: X25519MLKEM768
DONE
这段 OpenSSL 3.6 的输出已经说明了大半:TLS 1.3、AES-256-GCM 套件、ECDSA P-256 证书签名、证书链验证通过、密钥交换用的是后量子混合算法。macOS 自带的 openssl 其实是 LibreSSL,想看到上面的字段请用 Homebrew 安装的 OpenSSL 3。curl -v https://example.com/ 也会打印类似信息。STARTTLS、客户端证书、强制指定版本等更多用法见连接测试命令手册,想要完整体检可以用 SSL 检测工具。
常见误区
“证书负责加密流量。” 不对。证书私钥只用来给握手签名,流量是用临时密钥交换得到的会话密钥加密的。所以私钥泄露也解不开以前的 TLS 1.3 会话。
“RSA 密钥越长,加密越强。” 证书密钥长度影响的是服务器身份认证的强度,和数据加密算法是两回事。截至 2026 年 11 月,2048 位 RSA 或 P-256 ECDSA 证书都够用,数据加密算法另行协商(见密码套件)。
“只有登录页需要 HTTPS。” 没有 TLS,链路上任何一跳都能读 Cookie、往页面里注入脚本。浏览器会把纯 HTTP 标记为“不安全”,HTTPS 页面里的混合内容也会被拦截。
“配好一次就一劳永逸。” 证书会过期,而且最长有效期在不断缩短:2026 年 3 月 15 日起从 398 天降到 200 天,2027 年 3 月 15 日降到 100 天,2029 年 3 月 15 日降到 47 天。用宝塔面板的话可以开启自动续签,自建服务器就要配 ACME 客户端,详见 47 天证书和证书自动续期。
常见问题
SSL 和 TLS 是一回事吗?
TLS 是 SSL 的后继者。SSL 2.0 和 3.0 早已被禁用(RFC 6176、RFC 7568),今天的 HTTPS 连接用的都是 TLS 1.2 或 TLS 1.3。"SSL 证书"只是沿用下来的叫法,证书本身是 X.509 证书,和协议版本无关。
用了 HTTPS,别人还能看到我访问了哪个网站吗?
能看到一部分。TLS 加密了 URL 路径、参数、请求头和正文,但服务器 IP 是公开的,域名通常也会出现在 DNS 查询和 ClientHello 的 SNI 字段里。只有站点启用 ECH、客户端同时使用加密 DNS 时,域名才会被隐藏。
上 HTTPS 会让网站变慢吗?
几乎感觉不到。现代 CPU 有 AES 指令,对称加密每秒能处理数 GB 数据;TLS 1.3 新连接只多 1 个往返,会话恢复配合 0-RTT 甚至不增加往返。国内访问慢通常是网络链路和跨境线路的问题,不是加密本身。
浏览器有小锁,就说明网站可信吗?
不是。小锁只表示连接已加密、服务器证明了自己控制这个域名,和网站经营者是否靠谱无关。钓鱼网站同样可以拿到有效证书。
资料来源
- RFC 9846: The Transport Layer Security (TLS) Protocol Version 1.3(2026 年 7 月)
- RFC 8446: TLS 1.3 最初版本(已被 RFC 9846 取代)
- RFC 5246: The TLS Protocol Version 1.2(已被 RFC 9846 取代)
- RFC 8996: Deprecating TLS 1.0 and TLS 1.1
- RFC 9001: Using TLS to Secure QUIC
- RFC 9113: HTTP/2
- RFC 8998: ShangMi (SM) Cipher Suites for TLS 1.3
- OpenSSL 文档:openssl-s_client