入门基础

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)签名。握手时客户端会:

  1. 收到服务器证书和中间证书;
  2. 从服务器证书一路向上构建证书链,直到操作系统或浏览器信任库里的某个根证书;
  3. 检查访问的域名是否在 SAN 里、当前时间是否在有效期内、密钥用途是否允许 TLS 服务器认证,并视客户端而定检查吊销状态和证书透明度证明;
  4. 验证服务器用私钥对握手记录所做的 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 甚至不增加往返。国内访问慢通常是网络链路和跨境线路的问题,不是加密本身。

浏览器有小锁,就说明网站可信吗?

不是。小锁只表示连接已加密、服务器证明了自己控制这个域名,和网站经营者是否靠谱无关。钓鱼网站同样可以拿到有效证书。

资料来源

  1. RFC 9846: The Transport Layer Security (TLS) Protocol Version 1.3(2026 年 7 月)
  2. RFC 8446: TLS 1.3 最初版本(已被 RFC 9846 取代)
  3. RFC 5246: The TLS Protocol Version 1.2(已被 RFC 9846 取代)
  4. RFC 8996: Deprecating TLS 1.0 and TLS 1.1
  5. RFC 9001: Using TLS to Secure QUIC
  6. RFC 9113: HTTP/2
  7. RFC 8998: ShangMi (SM) Cipher Suites for TLS 1.3
  8. OpenSSL 文档:openssl-s_client