§ 4.4 · Section

TLS 握手

Transport Layer Security · RFC 8446

上一步通道打通了,但这条通道是敞开的——路上任何一台设备都能看见你说什么,甚至能改。这一节要在这条通道上再套一层加密壳,并且解决一个更难的问题:怎么确认对面那台机器真的是它自称的那个。地址栏那把小锁,就是这一节的成果。

生活场景
🏦 你到了柜台,但你怎么知道这是真银行

你按着地址找到了一家"银行",门开着,柜员坐在里面。你正要报出账号和密码——等一下,你凭什么相信这是真的银行?

可能它是真的。也可能这栋楼昨天刚被人租下来,装了一模一样的招牌、印了一样的单据、柜员穿着一样的制服。

你怎么验?看它墙上挂的营业执照。但假的也能印一张执照。所以真正管用的是:执照上有工商局的公章,而那个公章你有办法验真。

验完身份还有第二个问题:大厅里坐着一堆人。你把密码念出来,旁边全听见了。所以你和柜员还得先约定一套只有你俩懂的暗语,后面的对话全用暗语说。

TLS 握手干的正是这两件事:验明对方身份(靠证书链)+ 约定一把只有你俩知道的钥匙(靠密钥协商)。而最神奇的地方在于——这套暗语是在所有人都听得见的大厅里当众商定的,旁听者却推不出来。这一节会讲清这是怎么做到的。

上一步刚完成了什么,这一步要干什么

接力棒交到这一节手上时,手里有的是:一条已经建好的 TCP 连接(§ 4.3 的产物)。这条连接能可靠地传字节——不丢、不重、按序,但完全不保密,也完全不验证对方身份

为什么必须补上这两件事?因为一条纯 TCP 连接有三个致命缺口:

所以这一节要干三件事,一件都不能少:

目标专业说法换成大白话靠什么实现
别人看不见机密性(Confidentiality)说白了就是"说话用暗语,旁人听不懂"对称加密(双方共用一把钥匙)
别人改不了完整性(Integrity)说白了就是"内容被动过一个字,我立刻知道"消息认证码 / 带认证的加密
对方不是冒充的身份认证(Authentication)说白了就是"你得拿出别人验得了真的执照"数字证书 + 证书链

这三件事里最容易被忽略、也最关键的是第三件。因为前两件如果没有第三件兜底,就毫无意义——你跟一个骗子建立了一条完美加密的通道,加密只保证了没有第三个人偷听你俩,而骗子本人当然全听得见。

干完之后交给下一节的东西是:一条加密通道,加上一个已经验明身份的对端。此后所有 HTTP 报文都从这条通道里过,路上谁都看不懂。

先把这一节的术语翻译成人话

这一节的术语密度是全章最高的,而且几乎全是密码学词汇。别慌——它们本质上都是"锁、钥匙、印章、执照"这几样东西的变体。先过一遍这张表:

术语换成大白话生活里对应的东西
TLS(Transport Layer Security,传输层安全协议)说白了就是"在普通通道外面套的那层保险管道"普通信 vs 挂号加密邮件:内容封在专用封套里,还能验寄件人
SSL(Secure Sockets Layer,TLS 的旧名)说白了就是 TLS 的老名字,早已被取代但称呼留下来了某个机构改了名,但老百姓还叫老名字
HTTPS说白了就是"HTTP 装进 TLS 管道里跑",不是另一个协议同一封信,从平邮换成挂号加密件——信的内容格式没变
对称加密(Symmetric Encryption,加解密用同一把钥匙)说白了就是"同一把钥匙既能锁也能开"家里的钥匙:一把钥匙锁门也开门,快,但得先把钥匙交到对方手上
非对称加密(Asymmetric Encryption,公钥私钥一对)说白了就是"一把只能锁、一把只能开"小区的信箱:投信口人人能投(公钥),但只有住户的钥匙能打开取信(私钥)
公钥(Public Key)说白了就是"到处公开都没关系的那一半"你家信箱的投信口——谁都能看到、谁都能用
私钥(Private Key)说白了就是"绝不能给别人的那一半"信箱那把钥匙——给出去就等于把信箱交给别人
数字证书(Certificate)说白了就是"一张写着'这个公钥属于这个域名'的官方证明"银行墙上挂的营业执照:证明"这家店确实是这家公司"
CA(Certificate Authority,证书颁发机构)说白了就是"给证书盖章的那个权威机构"工商局:它盖的章大家都认,所以执照才有意义
证书链(Certificate Chain)说白了就是"我的章是他盖的,他的章是更上面那位盖的"分公司的证明由总公司背书,总公司的资质由国家机构背书
根证书(Root Certificate)说白了就是"这条链条最顶上那个不需要别人证明的"国家机构自己的印章——它就是最终标准,没有更上级
数字签名(Digital Signature)说白了就是"用私钥盖的一个只有本人能盖、谁都能验的章"手写签名加骑缝章:别人模仿不了,但人人可以拿去比对
密钥协商(Key Exchange / Agreement)说白了就是"当众商定一句只有咱俩懂的暗语"两人在嘈杂会议室里,用一套办法约定暗号,旁听者听全了也推不出来
会话密钥(Session Key)说白了就是"这一次通话专用的那把钥匙,挂了就废"一次性的临时门禁卡,当天有效
加密套件(Cipher Suite)说白了就是"这次用哪套加密方案的组合清单"点菜的套餐组合:主菜+配菜+汤,整套一起定
SNI(Server Name Indication,服务器名称指示)说白了就是"我进门先说清我要找哪家店"一栋楼里有二十家公司共用大门,你进门得先跟保安说找哪家
前向保密(Forward Secrecy)说白了就是"就算以后我的钥匙被偷了,也解不开以前录下的通话"每天换一次门牌密码,且旧密码不能反推——今天的锁被撬也翻不出上月的账

这张表里最该先弄明白的是对称加密与非对称加密的分工,因为整个 TLS 的设计就建立在它们的取舍上。对称加密快但要先把钥匙送到对方手里;非对称加密不用送钥匙但慢得多。TLS 的解法非常聪明:用慢的那套去安全地商定一把钥匙,然后用快的那套来传实际数据。

换成大白话:先用一趟郑重的、慢的、有保障的流程把暗语定下来,之后的所有对话就用这个暗语飞快地说。如果全程都用慢的那套,网页会慢到不可用;如果全程都用快的那套,第一步"怎么把钥匙给对方"就无解。

Analogy · 公钥私钥就是"小区的信箱"

非对称加密是这一节最抽象的概念,但有一个类比能让它立刻变得具体:小区门口那排信箱。

投信口是公开的——它就在楼下大厅,任何人经过都能看到,任何人都能往里塞东西。这就是公钥:可以印在名片上、贴在网站上、发给全世界,一点风险都没有。

但打开信箱的钥匙只有住户有。这就是私钥:一旦交给别人,整个信箱的保密性就归零了。

这个结构带来一个非常反直觉但极重要的性质:"能锁"和"能开"被彻底分开了。你可以让全世界都有能力给你上锁,同时保证只有你能解开。在这之前,人类几千年的加密史里,能加密就等于能解密——这一个分离是二十世纪最重要的发明之一。

数字签名是这个结构反过来用:用私钥"盖章",用公钥"验章"。因为只有你有私钥,所以只有你盖得出这个章;而因为公钥人人都有,所以人人都能验证"这章确实是他盖的"。相当于一枚全世界都能查验真伪、却只有你一个人能刻出来的印章

证书的整套机制就建立在这上面:CA 用它的私钥给网站的证书盖章,你的浏览器用 CA 的公钥去验这个章。章验得过,就说明这份证书确实是那个 CA 签发的,不是伪造的。

TLS 1.3 握手:一个来回办完所有事

现在看真实流程。TLS 1.3(由 RFC 8446 定义)把握手压到了一个来回(1-RTT),这是它相对 1.2 最大的进步。完整过程是这样:

你的浏览器                                       服务器
(TCP 连接已建好)                            (TCP 连接已建好)
     │                                              │
     │ ①  ClientHello                               │
     │ ─────────────────────────────────────────→  │
     │   带上:· 我支持 TLS 1.3                       │
     │        · 我支持这些加密套件(一份清单)           │
     │        · 一个随机数                            │
     │        · SNI:我要访问 shop.example.com        │
     │        · ★ 密钥共享:我这一半的临时公开值          │
     │                                              │
     │ ②  ServerHello + 证书 + Finished              │
     │ ←─────────────────────────────────────────  │
     │   带上:· 就用 TLS 1.3,加密套件选这个            │
     │        · 一个随机数                            │
     │        · ★ 密钥共享:我这一半的临时公开值          │
     │        · 我的证书(以及中间证书,组成证书链)        │
     │        · 用私钥做的签名(证明我真持有这份证书)      │
     │        · 从这条消息的后半段开始,内容已经是加密的     │
     │                                              │
     │ ③  (本机计算)验证证书链、算出会话密钥              │
     │                                              │
     │ ④  Finished(已加密)                          │
     │ ─────────────────────────────────────────→  │
     │        "我验完了,密钥算好了,可以开始了"           │
     │        ★ 这个包后面可以直接跟上 HTTP 请求          │
     │                                              │
  加密通道就绪                                加密通道就绪

耗时:① 到 ② 是一个完整来回(1 RTT)。
      ④ 不需要等回应,可以跟第一个 HTTP 请求一起发。
      所以 TLS 1.3 的握手成本 = 一个 RTT。

这里最巧妙的设计是第 ① 步就把自己那一半的"密钥材料"发出去了。TLS 1.2 的做法是先商量用什么算法、等对方回复了再交换密钥材料,所以要两个来回。TLS 1.3 的思路是:我先猜你大概会选哪套方案,把材料一次带上;猜对了就一个来回搞定。

换成大白话,这个区别相当于两种去银行办事的方式:

代价是你可能白带了几样材料(如果猜错了服务器支持的方案,还得多一个来回补救),但绝大多数时候能猜对,所以平均下来省了整整一个来回。这种"乐观预测 + 猜错才回退"的设计手法在协议优化里非常常见。

TLS 1.2 与 1.3:差的不只是一个来回

把两个版本摆在一起对比,能看出协议演进的完整思路。1.3 不是给 1.2 加功能,而是大幅删减——它砍掉了几十年积累下来的历史包袱。

TLS 1.2TLS 1.3(RFC 8446)为什么改
完整握手轮次两个 RTT一个 RTT客户端第一条消息就带上密钥材料,不再"先商量后交换"
会话恢复约一个 RTT支持 0-RTT(重连时可在第一个包里就带数据)老客户重连不该再等一个来回
可选的密钥交换方式很多种,包括已知不安全的只保留基于椭圆曲线等现代方案的少数几种选择越多,配错的机会越多——历史上多数 TLS 事故源于配了不该用的套件
前向保密可选(不少部署没开)强制私钥泄露就能解密历史流量,这个风险太大,不该是可选项
握手内容是否加密大部分明文,包括证书ServerHello 之后就开始加密,证书也被加密连"你在访问哪个站"这类信息也该少泄露
过时算法还允许一批老算法全部移除兼容老东西的代价是给攻击者留了降级空间

这张表里最值得体会的是第三行和第六行:TLS 1.3 的主要安全提升,来自"删掉选项"而不是"增加强度"。

为什么删选项能提升安全?因为真实世界里绝大多数安全事故不是"算法被破解了",而是"有人配错了、或者被诱导降级到了一个弱方案"。打个比方,这相当于一台机器上有二十个按钮,其中三个是危险操作。你可以贴警告标签、写操作手册、培训员工——但只要按钮还在,早晚有人按错。最有效的办法是把那三个按钮直接拆掉。

这个思路值得记住,它在安全设计里叫"减少攻击面":说白了就是"能删掉的功能就是最安全的功能"。同样的道理也解释了为什么 § 4.1 讲的 HSTS 要"不给明文请求任何机会"——不是加强明文的防护,而是让明文压根不发生。

0-RTT:重连时连一个来回都不等

TLS 1.3 还有一个更激进的模式叫 0-RTT(Zero Round Trip Time,零往返时间)。它的意思是:如果你以前连过这台服务器,重连时可以在第一个包里就把数据发出去,不等任何回应。

原理是服务器上次会给你一张"票"(Session Ticket,会话票据),里面加密存着上次协商的信息。你下次带着这张票来,双方就能直接复用之前的密钥材料。

相当于健身房的老会员:第一次去要填表、拍照、办卡(完整握手);此后每次刷卡进门,连招呼都不用打(0-RTT)。

但 0-RTT 有一个必须知道的固有缺陷,而且这个缺陷是设计上无法完全消除的:0-RTT 发出的那份数据可能被重放。

攻击者的做法:
  ① 在路上把你那个 0-RTT 数据包(连同票据)原封不动地复制下来
  ② 过一会儿,把这个完整的包再发一次给服务器
  ③ 服务器无法判断这是不是你本人又发了一次

★ 为什么无法判断?因为 0-RTT 的整个卖点就是"不需要来回确认"。
  而"确认对方是活的、这不是录音重播"这件事,
  本质上就需要一个来回(服务器发个随机数、你用它回一次)。
  ——不等来回,就必然失去这种确认能力。

换成大白话:这相当于用录音开门。你对着门喊一句暗号就能进,方便得很;但有人在旁边录了音,回头放一遍,门也开了。要防住录音重播,唯一办法是让门先随机问一句"今天几号"——而那就多了一个来回,0-RTT 的意义也就没了。

所以规范和实践上的处理办法是限制 0-RTT 能用来干什么只允许发送"重复执行也无害"的请求。比如"给我看看首页"这种,重放一百次也只是多读了一百次;而"给我转账一千块"这种绝对不行,重放一次就多转一千。

这个区分在技术上有个专门的词叫幂等(Idempotent,"做一次和做多次结果相同")。相当于"按一下电梯上行键"是幂等的(按十次也是上一次),而"从柜台取五百块"不是幂等的(做十次就少了五千)。0-RTT 只适合前者。这也是 § 4.5 会讲到的 HTTP 方法幂等性的实际用途之一。

证书链验证:那把小锁背后的完整逻辑

现在讲这一节最核心、也最容易讲糊的部分:浏览器凭什么相信这份证书?

先看一份证书里到底有什么。它本质上就是一张写满字的表格,关键几栏是:

字段内容相当于执照上的哪一栏
Subject(主体)这份证书是发给谁的,含域名企业名称与经营场所
SAN(Subject Alternative Name,主体备用名称)这份证书对哪些域名有效(可以是多个,也可以是 *.example.com 这样的通配)营业执照上列的所有分店地址
Public Key(公钥)这个域名的公钥——整份证书的核心就是为了把"域名"和"这个公钥"绑在一起企业的公章样本(大家拿它去比对)
Issuer(颁发者)是哪个 CA 签发的由哪个工商局核发
Validity(有效期)从哪天到哪天有效执照的有效期限
Signature(签名)颁发者用自己私钥对上面全部内容做的签名工商局盖的那个骑缝章

浏览器的验证过程是四步,缺一步都不算通过:

① 域名对不上?—— 你访问的是 shop.example.com,
   那这个域名必须出现在证书的 SAN 列表里。
   ★ 这是最容易触发警告的一条:证书是给 www.a.com 的,
     你却访问 a.com(不带 www),就会报错。

② 过期了吗?—— 当前时间必须在有效期内。
   ★ 有意思的后果:如果你电脑的时间设错了(比如设成 2050 年),
     所有网站都会报证书过期。这是"HTTPS 全站打不开"的一个经典原因。

③ 签名验得过吗?—— 用颁发者的公钥去验这份证书上的签名。
   验得过 → 说明这份证书的内容一个字都没被改过,
            而且确实是那个颁发者签的。

④ 颁发者可信吗?—— 这是最关键的一问。
   颁发者也有自己的证书,那份证书又是谁签的?
   于是往上追一层,再验一次第 ③ 步……
   一直追到某一份"根证书",
   而根证书就存在你的操作系统或浏览器里,是预置信任的。

★ 这条一层层往上追的路径,就叫「证书链」。
  只要链条上任何一环验不过,整条链就废,浏览器立刻报警。

一条典型的证书链有三层:

  根证书(Root CA)
     │  它的私钥签发了 ↓          ← 这一份预装在你的设备里,是信任的起点
  中间证书(Intermediate CA)
     │  它的私钥签发了 ↓          ← 服务器会连同自己的证书一起发给你
  网站证书(shop.example.com)
                                 ← 就是这一份把域名和公钥绑在了一起

为什么要多一层"中间证书",不让根证书直接签?因为根证书的私钥太宝贵了——它是全世界信任的起点,一旦泄露,整个体系崩塌。所以正规做法是把根私钥锁在离线的保险设施里,几乎不动它,日常签发工作交给中间 CA。

换成大白话:这相当于国家最高印章不会天天拿出来盖普通文件。它只盖一次——用来授权省级机构;省级机构再去盖那千千万万份日常文件。好处是:如果某个省级机构出了问题,只要吊销它那一份授权就行,不需要动最高印章、也不影响其他省。而如果所有文件都用最高印章直接盖,那一旦最高印章有问题,全国所有文件同时作废。

Analogy · 证书链就是"谁给谁背书"的一条链条

假设你要验证一位陌生人的身份,他递给你一张工牌,上面写着"某公司 · 技术部 · 李建国"。

你会怎么验?你不认识这个人,也不认识这家公司。但你可以问:"这张工牌是谁开的?"他说是某公司人事部。"人事部凭什么?"因为这家公司在工商局注册过。"工商局凭什么?"——到这里你就停了,因为工商局是你本来就认的机构,不需要再往上问。

这就是证书链的全部逻辑:一路往上问"谁给你背书",直到问到一个你本来就信的人为止。

而"你本来就信谁"这件事,在浏览器里是预置的——你的操作系统和浏览器里装着一份根证书清单(通常一两百份),那些机构就是"你本来就认的工商局"。这份清单不是你自己挑的,是系统和浏览器厂商替你挑的。

这带来一个非常重要、也常被忽略的推论:HTTPS 的安全性,最终建立在"你相信设备里那份根证书清单没被动过"这个前提上。

所以如果有人能往你的设备里塞一份自己的根证书(比如公司发的电脑上装的管理软件、某些声称"能加速上网"的工具),那他就能给任何域名签发一份浏览器认可的证书,你的所有 HTTPS 流量他都能看。相当于有人偷偷往你脑子里塞了一句"某某民间组织也算工商局"——从此他印的执照你全都认。

这就是为什么"随便安装根证书"是极高风险的操作,也是为什么公司电脑上的加密流量并非对公司保密。

密钥协商:在人人都听得见的地方约定暗语

这是 TLS 里最让人惊奇的一部分:你和服务器在一条所有人都能监听的通道上对话,最后却得出了一个只有你俩知道的数。怎么可能?

完整的数学不在本章展开(那属于密码学),但它的结构可以用一个类比讲得很清楚。它的名字叫 Diffie-Hellman 密钥交换(以两位发明者命名,1976 年提出)。

打个比方,用调颜色来说明:

你和对方要在众人围观下约定一个"只有你俩知道的颜色"。

① 你俩公开商定一个起始色:黄色。(所有人都听到了:黄色)

② 你私下选一个秘密色:红色。 (只有你知道)
   对方私下选一个秘密色:蓝色。(只有他知道)

③ 你把「黄 + 红」调好,得到橙色,公开寄给对方。
   对方把「黄 + 蓝」调好,得到绿色,公开寄给你。
   (所有人都看到了:橙色和绿色)

④ 你把收到的绿色,再加上你的秘密红色 → 得到「黄+蓝+红」
   对方把收到的橙色,再加上他的秘密蓝色 → 得到「黄+红+蓝」
   ★ 两边得到的是同一个颜色!

⑤ 而旁观者手上只有:黄色、橙色、绿色。
   他要算出「黄+红+蓝」,就必须先从橙色里把红色分离出来——
   而"把调好的颜色重新分解成原料"这件事极其困难。

这就是全部诀窍:混合容易,分离极难。

真实的数学里,"混合"是模幂运算,"分离"是离散对数问题——前者电脑瞬间算完,后者用现有算力在合理时间内做不到。整个现代加密体系就建立在这类"正着算容易、反着算极难"的问题上。

换成大白话:这相当于把一杯咖啡和一杯牛奶倒在一起——一秒钟就混好了,但要把它们重新分开,难度是另一个量级。所有人都看到你倒了什么进去混合物,却没人能把混合物拆回原料。

这套机制还带来一个极重要的性质,叫前向保密(Forward Secrecy):因为每次连接用的"秘密色"都是临时随机生成、用完就扔的,所以即使将来服务器的私钥被偷了,攻击者也解不开他之前录下的通话内容。

相当于你和对方每次见面都现场约定一个新暗语,而且约完就把纸条烧掉。就算十年后有人偷到了你家的钥匙,也翻不出这些对话——因为那些暗语从来没有被存在任何地方。TLS 1.3 把前向保密变成了强制而非可选,这是它安全性上最大的提升之一。

SNI:一栋楼二十家公司,你得先说找哪家

握手的第一条消息 ClientHello 里有一个字段叫 SNI(Server Name Indication,服务器名称指示),内容就是你要访问的域名。为什么要在这里再说一遍域名?不是已经通过 DNS 找到 IP 了吗?

因为一个 IP 上常常住着很多个网站。共享主机、CDN 节点、云服务器上一个 IP 挂几十上百个域名是常态。服务器收到握手请求时面临一个难题:我该拿哪份证书给他?我这儿有二十份证书,分属二十个不同域名。

这是个死结:证书要在握手时发出去,可"该发哪一份"这个信息在 HTTP 请求里(Host 头),而 HTTP 请求要等握手完成、加密建立之后才能发。鸡生蛋、蛋生鸡。

SNI 就是解这个死结的:在握手的第一句话里,明文告诉服务器"我要找的是 shop.example.com",服务器就知道该拿哪份证书了。

换成大白话:这栋写字楼里有二十家公司共用一个大门。你进门时保安问"找哪家",你得先说清,他才知道该带你去哪层、该出示哪家的接待流程。你不能进门就要求"先给我看你们的营业执照"——保安会反问"你要看哪家的?"

但 SNI 有一个至今存在的隐私缺口:它是明文的。也就是说——即使你的所有通信内容都被加密了,"你正在访问哪个域名"这件事仍然暴露在路上。

信息HTTPS 下路上的人能看到吗说明
你访问的域名(通过 SNI,也可能通过 DNS 查询)这是最大的隐私缺口
目标服务器的 IP包头上就是明文,必须如此才能路由
你访问的具体路径不能/item/8848 在加密内容里
你提交的账号密码不能在加密内容里
返回的页面内容不能在加密内容里
传输的数据量与时间模式能(间接推测)加密隐藏内容,但隐藏不了"有多少、什么时候"

这张表值得记住,因为它精确划出了 HTTPS 保护的边界。一个常见误解是"用了 HTTPS 别人就完全不知道我在干什么"——不对,别人知道你去了哪家店,只是不知道你在店里买了什么。

相当于你走进一家挂号大厅,外面的人看得见你进了哪个科室的门,但听不见你和医生说了什么。"去了哪儿"是暴露的,"说了什么"是保密的。业内有加密 SNI 的方案在推进,但本文不对其部署状况下结论。

证书出问题时浏览器会说什么:五种警告的真实含义

这一节最实用的部分。浏览器的证书警告是普通用户最常遇到、也最常被无脑点"继续访问"的东西。下面五种含义完全不同,其中有的可以忽略,有的绝对不能。

警告真实含义危险程度常见的真实原因
证书已过期有效期已过中——可能只是网站忘了续,但也可能是你的系统时间错了网站运维忘续期;或你设备时间不对(先去检查这一项)
域名不匹配证书上的域名不含你访问的这个中到高访问了 a.com 而证书只给了 www.a.com;或者你真的连到了别人的服务器
颁发者不受信任追不到你设备里任何一个根证书自签名证书(开发环境常见);或有人在中间拦截
证书已被吊销CA 明确宣布这份证书作废了极高该证书的私钥已泄露——继续访问等于明知有诈还上门
混合内容(Mixed Content)页面本身是 HTTPS,但里面引用了 HTTP 资源网站改造不彻底。危险在于那些 HTTP 资源可被篡改

关于"要不要点继续访问",有一条很简单的判断标准:如果这个页面你要输入任何东西(账号、密码、验证码、地址),一律不要继续。如果只是看看公开内容,风险相对低。

换成大白话:只是路过看看橱窗,店铺的执照有点问题也就罢了;但你要往里交钱、报身份证号,那执照必须验得过,一点含糊都不能有。

这里还要澄清一个特别重要的点:"证书有效"和"网站是好人"是两件完全不同的事。证书只证明"这个域名确实归这份公钥的持有者",它不证明这家网站诚实、不欺诈、不卖假货。

相当于一家店的营业执照货真价实,但它可能就是一家专门骗人的店——执照证明的是"它确实是登记的那家公司",不是"它做的生意是好生意"。所以钓鱼网站也可以有一把合法的绿色小锁,只要它注册了一个自己的域名。看到小锁不等于安全,只等于"你确实连到了地址栏上那个域名"——而地址栏那个域名本身可能就是伪装的(这正是 § 4.1 讲的同形字攻击)。

整节小结:TLS 握手的完整时间线

把本节内容按真实顺序串起来,接在 § 4.3 的第 ⑦ 步之后:

接过一条已建好的 TCP 连接(目标 443 端口)
  │
  ├─① 查会话缓存:以前跟这台服务器握过手吗?
  │      有票据 → 走会话恢复,可能是 0-RTT(几乎不花来回)★
  │      没有   → 完整握手,继续
  │
  ├─② 发 ClientHello:我支持的版本、加密套件清单、随机数、
  │      SNI(明文的域名)、我这一半的密钥材料
  │
  ├─③ 收 ServerHello:定下版本与套件、服务器随机数、
  │      服务器那一半的密钥材料、证书链、签名
  │      —— 这条消息的后半段起,内容已经加密
  │
  ├─④ 本机验证证书链(不占网络时间,占 CPU)
  │      · 域名对得上吗(看 SAN)
  │      · 在有效期内吗
  │      · 每一层签名验得过吗
  │      · 最终追到的根证书在我信任的清单里吗
  │      任何一项失败 → 弹警告,流程中断
  │
  ├─⑤ 双方各自用「自己的秘密 + 对方的公开值」算出同一把会话密钥
  │      —— 这把密钥从未在网络上传输过,这是整套设计的精髓
  │
  ├─⑥ 发 Finished(加密的),可以跟第一个 HTTP 请求一起发
  │
  └─⑦ 加密通道就绪 → 发 HTTP 请求 → 这就是 § 4.5 的起点

耗时量级:
  会话恢复 / 0-RTT   接近 0 到不足一个 RTT
  TLS 1.3 完整握手   约一个 RTT + 一点本机计算时间
  TLS 1.2 完整握手   约两个 RTT
  (证书验证本身不占网络来回,但要做若干次签名验算,占少量 CPU)

注意第 ① 步那个 ★ 号。和前面几节一样,最优的路径永远是"这活儿我以前干过,直接复用"。四节下来你应该已经看出这条贯穿全章的规律了:DNS 有缓存、TCP 有连接池、TLS 有会话票据、HTTP 有本地缓存——每一层都在拼命避免重复劳动。

说白了,整个网络栈的性能优化史,就是一部"想办法不干第二遍"的历史。

中间人攻击:TLS 到底在防谁

把 TLS 的三个目标放在一起看,你会发现它们共同针对的是同一个敌人:中间人(Man-in-the-Middle,简称 MITM——处在你和服务器之间、能看能改的那个角色)。

先看没有 TLS 时,这个角色能干什么:

正常情况:
   你  ←──────────────→  服务器

有中间人时:
   你  ←──→  中间人  ←──→  服务器
              │
              ├─ 能看:你发的密码、你看的页面,全部明文
              ├─ 能改:往页面里插广告、把下载包换成带毒的
              └─ 能冒充:他可以对你装成服务器、对服务器装成你
                          而双方都完全察觉不到

★ 最可怕的是第三条:双方都以为在跟对方直接说话。
  你输的密码,他先收下,再转发给真服务器;
  真服务器的回复,他看一眼,再转发给你。
  从"能不能用"的角度看,一切完全正常。

换成大白话:这相当于你和对方之间站了一个"翻译"。你说的话他翻给对方,对方的话他翻给你,业务办得顺顺利利——但他知道你们说的每一句,而且他随时可以在翻译时悄悄改几个字,你俩谁都不会发现。

那 TLS 是怎么挡住他的?关键不在加密,在证书。这一点值得反复强调,因为它是最常被误解的地方:

如果只有加密、没有身份认证如果有证书验证
中间人跟你建一条加密通道,再跟服务器建另一条他也可以这么试
两条都是"完美加密"的,没有第三者能偷听但他必须向你出示一份 shop.example.com 的证书
但中间人本人当然全看得见而他拿不出来——他没有那个域名的私钥,也没有任何 CA 会给他签这个域名的证书
结果:加密完全无效结果:浏览器报警,流程中断

所以"加密"防的是偷听,"证书"防的是冒充。没有证书,加密就是给骗子搭了个隔音包间。

相当于你和"翻译"关在一个隔音会议室里谈——外面的人一句听不见(加密有效),但那个翻译本人当然全知道。要挡住他,唯一办法是先验明"你到底是谁",而不是把房间修得更隔音。

这也解释了为什么 § 4.2 说 hosts 文件劫持在 HTTPS 时代威力大减:攻击者能把你的域名指向自己的服务器(DNS 层面得手了),但他没法在 TLS 层面拿出一份合法证书,所以最终还是过不了这一关。这是分层设计的一个漂亮之处:上一层的失守,可以由下一层补救。

HTTPS 到底"慢"不慢:一个过时的印象

早年有个流传很广的说法:HTTPS 比 HTTP 慢很多,所以只在登录页用就行。这个说法在今天已经基本站不住了,但很多人的印象还停在那里。值得把账算清楚。

HTTPS 相对 HTTP 的额外成本,就三笔:

反过来,HTTPS 带来的性能好处常常被忽略:现代协议的新特性(HTTP/2、HTTP/3 的多路复用等)在实践中往往只在加密连接上启用。所以在真实网站上,从 HTTP 换到 HTTPS 有时反而更快——因为顺带启用了更先进的传输机制。

换成大白话:过去的印象是"上锁要多花时间",现在的情况是"只有上了锁的门才配了自动感应和快速通道"。算总账反而更划算。

还有一个更根本的理由:"只在登录页用 HTTPS"这个做法本身是不成立的。因为登录之后你的身份凭证(Cookie)会随每个请求发出去,如果后续页面走明文,那凭证就在路上被看见了——相当于开户时锁着门办,办完之后把账号本子扔在大街上。所以现代做法一律是全站 HTTPS,配合 § 4.1 讲的 HSTS 强制执行。

动手看一次真实的握手

这一节讲的所有东西都能亲眼验证。三个动作,从易到难:

第一件:点开地址栏那把小锁。浏览器会显示这次连接用的 TLS 版本、加密套件、以及完整的证书链。值得点开看几次不同的网站——你会发现证书链的层数、颁发机构、有效期各不相同,而"从网站证书一路追到根证书"这条链条会以树状清清楚楚地列出来。

第二件:在开发者工具里看 TLS 耗时。

F12 → Network 面板 → 勾上 Disable cache → 刷新
   → 点第一条请求 → Timing 标签

其中 "SSL"(有的浏览器写 "TLS")那一段就是本节的全部耗时。

值得做的三组对比:
  ① 访问国内近距离站点 vs 跨国站点
     → SSL 段的差距主要来自物理距离(因为它是一个 RTT)
  ② 第一次访问 vs 短时间内再访问
     → 第二次这一段常常直接消失(连接复用或会话恢复)
  ③ 对比 Initial connection 与 SSL 两段
     → 它们通常量级相近,因为都是"一个来回"级别的开销

第三件:故意制造一次证书错误。最安全的做法是把系统时间改到很久以后(比如两年后),然后访问任意网站——你会看到大批网站同时报证书错误。这就验证了前面讲的"有效期检查"那一步是真的在跑,而且它检查的是你本机的时间。看完记得把时间改回来。

这个实验有实际用处:以后遇到"所有 HTTPS 网站都打不开"的情况,第一个该怀疑的就是系统时间不对——而不是重装浏览器。相当于整栋楼所有执照都显示过期,那大概不是二十家公司同时忘了续期,而是你手上那本日历翻错了年份。

Recap · 收束

这一节在已经打通的通道上做了三件事:让别人看不见(机密性)、改不了(完整性)、以及最关键的——确认对方不是冒充的(身份认证)。前两件如果没有第三件兜底就毫无意义,因为你可能跟骗子建了一条完美加密的通道。
核心机制一 · 公钥与私钥:像小区信箱——投信口公开(公钥),取信钥匙私有(私钥)。反过来用就是数字签名:只有我能盖、人人都能验。整个证书体系建立在这上面。
核心机制二 · 证书链:一路往上问"谁给你背书",直到追到设备里预置的根证书。四步验证缺一不可:域名对不对(看 SAN)、过期没、签名验得过没、最终追到的根在不在信任清单里。中间证书的存在是为了保护根私钥——某个中间机构出事只吊销它那一份,不影响全局推论:HTTPS 的安全性最终建立在"你设备里那份根证书清单没被动过"这个前提上——所以随便安装根证书是极高风险操作。
核心机制三 · 密钥协商:在人人都能监听的通道上约定出只有双方知道的密钥,靠的是"混合容易、分离极难"(调颜色的类比)。那把会话密钥从未在网络上传输过。而"每次用完就扔"带来前向保密——将来私钥泄露也解不开以前录下的流量,TLS 1.3 把它变成强制。
版本差异(RFC 8446):TLS 1.3 是一个 RTT,1.2 是两个 RTT;1.3 还支持重连时的 0-RTT(但有无法根除的重放风险,所以只该用于幂等请求)。1.3 的主要安全提升来自"删掉选项"而不是"加强算法"——因为事故大多来自配错和降级,而不是算法被破。
两条最该记住的边界:SNI 是明文的,所以 HTTPS 保护"说了什么",不保护"去了哪儿";② 证书有效 ≠ 网站可信——小锁只证明"你确实连到了地址栏那个域名",钓鱼网站一样能有合法证书。
下一步交出什么:一条已验明身份的加密通道。到这里,前三步的准备工作全部完成——终于可以开口说正事了。§ 4.5 就来看那句正事怎么说、对方怎么答。

☰ 主页
Xue Hai Wu Ya · Network · § 4.4 · TLS 握手