Caloogy 文章
English

TOFU 与公钥钉扎:第一次相信,以后都核对

日期
2026 年 11 月 2 日
系列
密码学
阅读
3 分钟
主题
TofuKey pinningSshSignal

一句话版本

怎么确认"跟我说话的就是上次那个人"?最朴素的办法叫 TOFU(Trust On First Use):第一次见面时记下对方的公钥,以后每次都和记下的比对,一旦变了就报警。 它不能防"第一次就被骗",但能把攻击窗口压缩到第一次那一刻。SSH 的 known_hosts、Signal 的安全码、手机 App 的证书钉扎,都是这个思路;更进一步的"密钥透明"则试图连第一次也保护起来。

全文分三层:

  1. 通俗理解:记住对方的长相
  2. 实际用处:SSH、Signal、App 证书钉扎、HPKP 的失败教训
  3. 原理与工程要点:钉什么、存在哪、变了怎么办,以及"服务器不可信"时的用法

第一层:通俗理解

1.1 记住对方的长相

你第一次去一家小店,记住了老板的长相。以后每次去,你都会下意识地看一眼:还是那个人。如果某天柜台后面突然换了一个陌生人,却声称自己就是老板,你会立刻起疑。

TOFU 就是这样:

  1. 第一次连接时,记下对方的公钥(或公钥指纹);
  2. 以后每次连接都和记下的比对;
  3. 不一致就停下来,大声警告。

1.2 它防什么,不防什么

情况 TOFU 的表现
攻击者第二次及以后才出现(中间人、服务器被换) 能发现
攻击者从第一次就在中间 发现不了:你记住的就是攻击者
对方合法地换了密钥(重装系统、换手机) 会误报,需要人去确认

所以 TOFU 的价值在于:攻击者必须从一开始就埋伏好,而这比"任何时候插一脚"难得多。


第二层:实际用处

Caloogy Wallet 也采用了公钥钉扎的思路。


第三层:原理与工程要点

3.1 钉什么

选择 优点 缺点
钉具体证书 最严格 证书一续期就失效
钉公钥(SPKI 指纹) 续期时可以复用同一把密钥 换钥匙要提前规划
钉 CA 灵活 保护弱:这家 CA 签的任何证书都会被接受

工程上一般钉公钥,并且同时钉一把备用公钥(离线保存),防止主钥匙丢失后把自己锁死。这正是 HPKP 失败的主要教训。

3.2 "服务器不可信"时的用法

TOFU 还有一个不太为人所知的用途:防自己的服务器被攻破。

设想用户在 App 里存了一份重要数据(比如一份共享的设置或名单),数据存在服务器上。如果服务器被攻破,攻击者可以悄悄改清单。对策:

  1. 清单的每一条都由用户设备上的私钥签名;
  2. 客户端第一次拿到用户公钥时,钉在本地;
  3. 以后每次读取清单,都用本地钉住的公钥验签;服务器给的公钥和本地不一致,就报警。

这样攻击者要么改不了清单(没有私钥),要么连公钥一起换(会被本地钉扎发现)。

3.3 变了之后怎么办

3.4 新设备的问题

换了新设备,本地没有任何记录,只能再"第一次相信"一次服务器。这个空窗期需要别的机制兜底,比如新设备上线后先进入一段只读期(见《冷静期》),并通知老设备。


总结

层次 要点
直觉 记住第一次见到的公钥,变了就报警
应用 SSH known_hosts、Signal 安全码、App 证书钉扎、密钥透明
教训 HPKP 因配置失误和锁死风险被废弃;要有备用钥匙
进阶 用本地钉扎发现"自己的服务器"被篡改;新设备空窗期要兜底