🛡️ 第五章 什么是密码、数字签名、数字证书
📄 一句话概括

中间人攻击的本质是"把两边的信任借过来"——你以为是直接和服务器说话,其实中间还站了一个人;它今天最需要重新认识的两点是:企业自己做的 TLS 拦截本质上是"被授权的中间人",而现代钓鱼式中间人(AiTM)已经不需要碰任何网络设备,它只需要一个代理域名——它能原样转发你的密码和短信验证码,只有把身份绑定到域名上的抗钓鱼认证(FIDO2/WebAuthn)才免疫。

📝 本节和前面几节的关系

5-7 讲了整套 TLS 握手,5-4 讲了证书链,5-8 讲了挂锁的边界。

这一节是本章的收尾,它要把前面所有零件装到一起回答一个问题:如果这条路被人拦住了,前面那些机制里哪些还管用、哪些立刻失效。 它也是整个第五章的落点——加密、签名、证书、哈希,最后都要回到"这两个端点之间到底站着谁"这件事上。

一、同样是"站在中间",能做和不能做差别极大

"中间人"这个词容易让人以为它是一种固定的攻击,实际上它是一段跨度极大的区间。攻击者能做什么,完全取决于两个端点之间有没有加密、以及加密有没有被真正强制。

场景 攻击者在中间能干的事 结果
完全明文(HTTP) 读、改、注入、重放请求 一切都看得见
加密但没 HSTS 第一次访问可被降级到明文 之后才被锁进 HTTPS
加密 + HSTS + 预加载 只能掐断连接,不能偷看 浏览器从不发明文请求

这张表最值得注意的是中间那一行——"加密但没 HSTS"。它揭示了一个非常反直觉的事实:即使你的网站已经全站 HTTPS,第一次访问仍然可能是被明文泄露的。 原因很简单:用户输入的是 example.com,不是 https://example.com。浏览器默认先试一个明文请求,由服务器用重定向把它推到 HTTPS——而这第一次的明文请求,就是攻击者下手的位置。

二、SSL 剥离为什么能成功

这道手法的名字叫 SSL 剥离(SSL stripping),它的巧妙之处在于"让双方都以为一切正常":

步 发生什么
1 你在公共 Wi-Fi 上照常输入 example.com(默认还是 http)
2 攻击者抢在服务器前应答,保持一个明文连接对你
3 同时自己另开一条真正的 HTTPS 连接去访问服务器
4 页面内容照常显示,但你和攻击者之间是明文的
5 服务器本来会发重定向到 https,被攻击者悄悄截掉

关键在于第 2 步和第 5 步:攻击者在"你这边"假冒服务器、在"服务器那边"假冒你,两条腿各自都是正常连接。第 5 步则是整件事能维持下去的关键——服务器发回的"请改用 https"这条重定向,被攻击者在中间摘掉了,所以你的浏览器一直以为这个站点就是用 http 访问的。页面能正常打开、内容完全正确、你也不会看到任何警告,因为从浏览器的角度看,它只是在访问一个普通的 http 网站而已。

防御就是 HSTS:浏览器记住【这个域名永远只走 HTTPS】,连第一次都不发明文请求(预加载列表把域名直接写进浏览器)。

这条机制值得体会一下它的思路:问题出在"浏览器主动发了第一个明文请求",那么解法就是"让浏览器从一开始就不发明文请求"。HSTS 是一个响应头(Strict-Transport-Security),浏览器收到之后会把它记在本地一段时间;而"预加载列表"更进一步——把域名直接写进浏览器内置的名单里,这样连你第一次访问、还没收到过那个响应头的时候,浏览器就已经知道只能走 HTTPS 了。这也是为什么只发一次 HSTS 响应头不够:那一次请求本身,就可能是被剥离的那一次。

三、动手 Demo:三种处境、两代中间人与八条防线

下面这段输出把上面两节做成对照表,接着讲一个常被忽略的事实(企业自己也在做中间人),最后给出八条按性价比排序的防线。

一、同样是【站在中间】,能做和不能做差别极大
  场景                      攻击者在中间能干的事        结果
  完全明文(HTTP)          读、改、注入、重放请求      一切都看得见
  加密但没 HSTS             第一次访问可被降级到明文    之后才被锁进 HTTPS
  加密 + HSTS + 预加载      只能掐断连接,不能偷看      浏览器从不发明文请求

二、SSL 剥离(SSL stripping)为什么能成功
  步    发生什么
  1     你在公共 Wi-Fi 上照常输入 example.com(默认还是 http)
  2     攻击者抢在服务器前应答,保持一个明文连接对你
  3     同时自己另开一条真正的 HTTPS 连接去访问服务器
  4     页面内容照常显示,但你和攻击者之间是明文的
  5     服务器本来会发重定向到 https,被攻击者悄悄截掉
  → 防御就是 HSTS:浏览器记住【这个域名永远只走 HTTPS】,
     连第一次都不发明文请求(预加载列表把域名直接写进浏览器)。

三、企业 TLS 拦截:一种被授权的中间人
  · 做法:把公司自己的根证书装进你的电脑,浏览器就会信任
     公司网关现场伪造的证书,挂锁照常显示
  · 2017 年一项研究分析了 80 多亿条被拦截的连接,结果:
     62% 的安全性低于不拦截时                    因为中间盒用了过时的加密库
     58% 的拦截连接带有严重漏洞                  中间盒自己不校验上游证书
  · NSA 明确警告:解密网关会变成【高价值攻击目标】——
     攻破它,等于拿到全公司流量的钥匙

四、AiTM 钓鱼:中间人已经不再需要碰网络设备
  你用的验证方式                    能不能挡住
  密码                              挡不住(被代理原样记录)
  短信验证码 / TOTP 动态码          挡不住(实时转发,在有效期内重放)
  FIDO2 / passkey 硬件密钥          挡得住(凭据与真实域名绑定,代理域名对不上)
  → 一条极重要的结论:多因子认证并不自动等于【能挡中间人】。
     只有把身份绑定到域名上的抗钓鱼认证(FIDO2 / WebAuthn)才真正免疫。

五、八条防线(按性价比排序)
  序号    措施
  1       强制 TLS 1.3,关掉 SSL 3.0 / TLS 1.0 / TLS 1.1
  2       开启 HSTS 并提交到预加载列表(连第一次访问也保护)
  3       给身份 Cookie 加 Secure 与 HttpOnly
  4       配置 CAA 记录,限定只有指定的 CA 能为你的域名签发证书
  5       关键移动应用用证书固定(pinning),并预先规划轮换
  6       对内网服务之间用双向证书(mTLS)
  7       上抗钓鱼的多因子认证(FIDO2 / WebAuthn),而不是短信验证码
  8       监控证书透明度日志,发现别人给你域名偷偷签证书

六、怎么发现(Detection)
  层次          信号
  终端          浏览器爆出证书错误;Windows 日志里反复出现 TLS 握手失败
  网络          本该走 HTTPS 的域名突然回退到 HTTP;ARP 表异常变动
  证书          地址栏里的签发 CA 突然变成公司自家 CA 或陌生 CA
  → 中间人最怕的就是【有人去看证书是谁签的】——挂锁不会告诉你,
     但证书链会。

第六节那句话是本节最实用的检测思路:中间人可以伪造证书、可以让挂锁照常显示,但他改不了"这张证书是谁签的"——除非他把自己的根证书装进了你的设备(那正是企业拦截的做法)。所以"去看证书链"这件事,是普通用户唯一能自己做的中间人检测手段(这也正好收回了 5-8 里"不要只看挂锁、要看完整域名"的那条建议)。

关于第五节的八条防线,值得说明为什么前两条排最前面:因为它们成本最低、阻断的攻击面最大。关掉 SSL 3.0 / TLS 1.0 / TLS 1.1 是一次配置,但能消灭掉一大批"用旧协议降级"的攻击;HSTS + 预加载同样是配置一次、长期生效,而它恰好堵住了 SSL 剥离这个最高频的手法。而"证书固定(pinning)"排在第五、还特意注明"要预先规划轮换",是因为它是一把双刃剑——它确实能挡住伪造证书,但一旦轮换计划没做好,你自己的应用会集体连线失败。HPKP(HTTP 公钥固定)这个曾经的浏览器标准就是因为"配错就永久锁死网站"而被废弃的,现在倾向于用证书透明度日志来替代它。

四、企业 TLS 拦截:一种被授权的中间人

这一节要讲一个很多人不知道的事实:企业网络里最常见的中间人,是企业自己。

做法本身很好理解:公司把自家的根证书装进每一台受管设备,然后让安全网关接管所有 HTTPS 流量——网关对你是"服务器"(用公司证书现场签一张给你,浏览器因为信任公司根证书所以不报警),对真正的服务器是"客户端"(另开一条真的 HTTPS 连接)。结果就是:挂锁照常显示,但内容在公司网关那里是明文的。

这么做的理由是真实的:要防数据外泄、要查恶意软件下载、要满足合规审计——不看见明文就做不到。但它的代价在 2017 年一项大规模研究里被量化得非常难看:

数据 含义
62% 的被拦截连接安全性低于不拦截时 中间盒用了过时的加密库
58% 的拦截连接带有严重漏洞 中间盒自己不校验上游证书

这两个数字值得仔细想:"拦截反而更不安全"不是偶然——因为中间盒必须同时支持一大堆老旧客户端,它往往只能用较旧的加密套件,于是把原本可以协商到 TLS 1.3 的连接,压低到了更弱的版本;而"中间盒自己不校验上游证书"意味着它把整个链路上最有价值的一道验证给取消了。换句话说,这道本该增加安全性的关卡,成了整条链路里最薄的一片。

更要紧的是 NSA 的警告:解密网关会变成"高价值攻击目标"——攻破它,等于拿到全公司流量的钥匙。 这是一个结构性的问题:为了逐一检查加密流量,你必须在网络里制造一个"能看到一切"的点,而这个点一旦失守,前面所有加密的努力同时归零。它把"端到端加密"这个安全属性,换成了"到一个中间点为止的加密"。

五、AiTM 钓鱼:中间人已经不再需要碰网络设备

这是 2026 年最需要更新认知的一段。 旧印象里的中间人要"在网络上做手脚"(ARP 投毒、劫持网关、假冒 Wi-Fi);而今天主流的中间人是钓鱼式的(AiTM,Adversary-in-the-Middle)——攻击者只搭一个代理站点,把你和真网站之间的每一次往返原样转发。

它能做到什么、不能做到什么,用一张表说最清楚:

你用的验证方式 能不能挡住
密码 挡不住(被代理原样记录)
短信验证码 / TOTP 动态码 挡不住(实时转发,在有效期内重放)
FIDO2 / passkey 硬件密钥 挡得住(凭据与真实域名绑定,代理域名对不上)

第二行是最反直觉、也最要紧的一行:很多人以为"我开了短信验证码就安全了",但 AiTM 会把你的验证码实时转发给真网站——攻击者不需要提前猜到那 6 位数字,他只需要在那 30 秒内把它转过去。这就是为什么"多因子认证"这个词在 2026 年已经不够用了,必须区分"能抗钓鱼的多因子"和"不能抗钓鱼的多因子"。

而 FIDO2 之所以能挡住,原因在它的一条设计约束上:它的凭据是和真实域名绑定的。当你在 login-example-secure.com(攻击者的代理域名)上尝试用 passkey 时,浏览器会发现"这里没有为这个域名注册过凭据",根本不会把签名发出去——攻击者拿不到能重放的东西。这也解释了一个容易被忽略的细节:FIDO2 的安全性不只来自"硬件",更来自"域名绑定"这个约束。

一条极重要的结论:多因子认证并不自动等于【能挡中间人】。 只有把身份绑定到域名上的抗钓鱼认证(FIDO2 / WebAuthn)才真正免疫。

六、⚠️ 2026 现状

1. 攻击形式已经从"ARP 投毒"转向"代理绕过云 MFA"。 过去讲中间人,重点是局域网内的技术手段(ARP 投毒、DNS 劫持、假冒热点);而现在规模更大的是"用一个反向代理站在你和真登录页之间",把密码与动态验证码实时转发过去,再顺带把会话 Cookie 拿到手——这样一来,"登录成功"这件事发生在真服务器上,任何日志都看不出异常。这类攻击已经在针对 Microsoft 365、Google 等云身份的大规模钓鱼中出现,并且直接绕过了短信与 TOTP 这类"不能抗钓鱼"的多因子。

2. 企业 TLS 拦截仍然普遍,但它的争议越来越大。 根证书装进受管设备、网关现场签证书、挂锁照常显示——这套做法在企业环境里依然常见,理由是合规审计、数据外泄防护、恶意软件检查。但"拦截反而更不安全"这个结论(62% 更低、58% 带严重漏洞)至今没有被推翻,而 NSA 关于"解密网关会成为高价值攻击目标"的警告,随零信任架构的推进反而更被重视——趋势是"不要在网络中间做全量解密",改用端点侧能力与应用层审计(对照 2-8)。

3. 证书固定(pinning)正在退位,证书透明度(CT)顶上来。 HPKP 因为"配置错误会永久锁死网站"已被浏览器废弃;移动应用里的证书固定仍然有效,但必须提前规划轮换(否则换证书的那天,所有旧版应用会集体连不上)。行业当前的倾向是"用 CT 日志监控"替代"在客户端死记某一本证书":因为 CT 是"任何人为你的域名签发证书都会留下公开记录",所以你能提前发现别人在冒充你(第 8 条防线的意义就在这儿)。

4. 对普通用户,唯一可操作的判断标准仍然是"看证书链"。 挂锁不会告诉你中间站着谁——它只证明"这一段连接被加密了"(这正是 5-8 的结论)。能自己动手做的三件事:① 看完整域名而不是看有没有锁;② 点开证书,看"颁发者"是不是一个说不清来历的机构(正常站点不会由"你的公司名"签发,除非你在被管理的设备上);③ 把密码管理器只在域名完全匹配时才自动填充这条设置留着——它是唯一不会被人眼忽略的防线。

30 秒实验

  1. 看一眼你现在访问的这个站点有没有开 HSTS。 打开浏览器的开发者工具(F12)切到「网络」面板,刷新页面,点最上面那个主文档请求,在「响应标头」里找 Strict-Transport-Security。如果看到 max-age=31536000; includeSubDomains; preload 这类内容,说明它开了 HSTS,而且大概率在预加载列表里;如果这一项完全不存在,那这个站点就还能被 SSL 剥离——你可以试着把地址栏里的 https:// 手动改成 http:// 访问一次,看它是不是自动跳到 https:能跳说明服务端有重定向,但少了 HSTS 这一步,第一次访问仍然不安全。

  2. 做一次"识别中间人"的练习。 点地址栏的挂锁 → 「证书」→ 看「颁发者」是谁。正常公开网站应该是某个公开 CA(Let's Encrypt、DigiCert、Google Trust Services 之类);如果你看到一家没听说过的公司、或者干脆是你所在单位的名字,那这条链路就被中间人接管了——它可能是公司合规审计,也可能是攻击者把根证书装进了你的设备。顺手再看一眼「证书路径」有几层:一个正常的公开站点通常有三层(根 → 中间 → 站点),只有两层本身就是简化的信号。

常见误区

  1. 错误:我的网站全站 HTTPS 了,所以不存在中间人。——纠正:问题出在第一次访问。用户输入的是域名而不是 https://,浏览器默认先发明文请求,由服务器重定向到 HTTPS——这第一次请求就是 SSL 剥离的下手位置。攻击者在你这边保持明文、在服务器那边开真 HTTPS,同时把服务器发回的重定向悄悄截掉,页面照常显示、你也看不到任何警告(因为从浏览器角度看,它只是在访问一个普通 http 网站)。要堵住这个缺口必须开 HSTS,还得用"预加载列表"把域名直接写进浏览器——因为只发一次 HSTS 响应头不够,那一次请求本身就可能已经被剥离了。

  2. 错误:我开了短信验证码/动态口令,所以中间人拿我没办法。——纠正:AiTM 钓鱼式中间人会把这些全都不当回事。它搭一个代理站点,把你和真网站之间的每一次往返原样转发——你的密码被原样记录,你的 6 位验证码被实时转给真网站,不需要提前猜到,只要在那 30 秒内转过去就行。能挡住它的只有"把身份绑定到域名"的抗钓鱼认证(FIDO2 / WebAuthn):你在攻击者的域名上尝试用 passkey 时,浏览器会发现这个域名没有注册过凭据,根本不会把签名发出去。所以"多因子认证"这个词在 2026 年已经不够用,必须区分"能抗钓鱼的"和"不能抗钓鱼的"。

  3. 错误:企业做 TLS 拦截是为了更安全,那它一定是更安全的。——纠正:2017 年那项分析了 80 多亿条被拦截连接的研究给出了相反的结论:62% 的被拦截连接安全性低于不拦截时,58% 带有严重漏洞。原因有两条:中间盒为了兼容一堆老旧客户端,只能用较旧的加密套件,把原本能协商到 TLS 1.3 的连接压低;而它自己往往不校验上游服务器的证书,等于取消了整个链路上最有价值的一道验证。更结构性的是 NSA 的警告:解密网关会变成"高价值攻击目标"——攻破它等于拿到全公司流量的钥匙。它把"端到端加密"换成了"到一个中间点为止的加密"。

  4. 错误:只要不用公共 Wi-Fi,就不会遇到中间人。——纠正:"不用公共 Wi-Fi"防的是局域网内的技术手段(ARP 投毒、DNS 劫持、假冒热点),而 2026 年规模更大的中间人是钓鱼式的,它根本不接触你的网络——你在自己家里的宽带、在自己手机上,只要点进一个代理域名并输入凭据,攻击照样成立。所以"我用的是安全的网络"这个判断,和"这次登录有没有被中间人接管"是两件无关的事。真正有效的判断只有一条:你面前的这个域名,和你以为的那个域名,是不是同一个(这正是 5-8 反复强调的那一点)。

自测三问(点开对答案) 1. SSL 剥离为什么能成功?防它的关键是什么? —— **因为"全站 HTTPS"并不等于"从不发明文请求"**。**用户在地址栏输入的是域名而不是 `https://`,浏览器默认先发一个明文请求,再由服务器的重定向把连接推到 HTTPS**——**这第一次请求就是下手位置**。**攻击者的手法是"两边各演一个角色"**:**在你这边保持明文连接、假冒服务器;在服务器那边另开一条真的 HTTPS 连接、假冒你**;**然后把服务器发回的"请改用 https"这条重定向悄悄截掉**。**结果页面照常显示、内容正确、也没有任何警告**,**因为从浏览器角度看它只在访问一个普通 http 网站**。**防它的关键是 HSTS**:**让浏览器记住"这个域名永远只走 HTTPS",连第一次都不发明文请求**;**而只靠响应头不够,必须提交到预加载列表,把域名直接写进浏览器**——**否则那一次请求本身就可能是被剥离的那一次。** 2. 为什么短信验证码挡不住 AiTM,而 FIDO2 挡得住? —— **因为两者的"可重放性"不同**。**AiTM 的中间人是一个代理站点,它会把你的每一次输入原样转发给真网站**——**密码被直接记录;6 位短信验证码或 TOTP 动态码被实时转发过去,攻击者不需要提前猜到它,只要在那个有效期内转过去就行**。**而 FIDO2 / WebAuthn 的凭据是和真实域名绑定的**:**你在攻击者的代理域名上尝试使用 passkey 时,浏览器会发现"这个域名没有注册过凭据",根本不会把签名发出去**,**攻击者拿不到任何可以重放的东西**。**所以 FIDO2 的安全性不只来自"硬件",更来自"域名绑定"这条设计约束**——**这也是"多因子认证"这个词今天必须再细分成"能抗钓鱼"和"不能抗钓鱼"的原因。** 3. 为什么"企业做 TLS 拦截"反而可能降低安全性? —— **有三个层面的原因**。**第一,中间盒为了兼容大量老旧客户端,只能用较旧的加密套件,于是把原本可以协商到 TLS 1.3 的连接压低了**——**2017 年那项分析 80 多亿条被拦截连接的研究里,62% 的被拦截连接安全性低于不拦截时**。**第二,中间盒自己往往不校验上游服务器的证书**,**等于取消了整条链路上最有价值的一道验证**——**58% 的拦截连接带有严重漏洞**。**第三,它制造了一个"能看到一切"的结构性弱点**:**整个公司的流量都要在这里解密,所以 NSA 明确警告解密网关会成为"高价值攻击目标"——攻破它等于拿到全公司流量的钥匙**。**换句话说,它把"端到端加密"换成了"到一个中间点为止的加密",而那个点本身成了最薄的一片。**

相关笔记