一句话版本
一个系统只要依赖单一的数据来源,那个来源出错、被攻破或者撒谎,系统就会"理直气壮地"做出错误决定。 对策有两层:多源交叉验证(问两家以上互相独立的来源,答案不一致就停下)和独立实现(关键计算由两份分别写成的代码各算一遍,防止同一个 bug 两边一起犯)。航空、航天、金融、区块链,都在用这个原则。
全文分三层:
- 通俗理解:只看一块手表的人
- 实际用处:波音 737 MAX、阿丽亚娜 5 号、DeFi 预言机攻击
- 原理与工程要点:怎样才算"独立"、不一致时怎么办、客户端独立复核
第一层:通俗理解
1.1 只看一块手表
航海时代有句老话:"出海要么带一块表,要么带三块,千万别带两块。"
- 一块表:错了你也不知道,但至少你会照着它走;
- 两块表:不一致时你不知道该信哪块;
- 三块表:少数服从多数,可以找出坏的那块。
在软件里,"两块表"其实也很有用,前提是把规则定成:不一致就停下来,不做决定。对于安全决策,"停下"往往比"选错"好得多。
1.2 两种不同的冗余
| 冗余 | 防什么 | 例子 |
|---|---|---|
| 多源:同一个问题问不同的来源 | 某个来源出错、被攻破、撒谎 | 两家不同公司的区块链节点 |
| 多实现:同一个计算由不同的代码算 | 自己代码里的 bug | 前端和后端各自独立计算金额 |
第二层:实际用处
| 事件 | 教训 |
|---|---|
| 波音 737 MAX(2018、2019) | 自动配平系统 MCAS 只读取一个迎角传感器。传感器故障时,系统反复把机头往下压,两起空难共 346 人遇难。改进后的设计改为比较两个传感器,不一致时停用 MCAS |
| 阿丽亚娜 5 号首飞(1996) | 火箭有两套惯性参考系统互为备份,但它们运行同一份软件,遇到同一个数值溢出 bug,几乎同时失效,火箭起飞约 40 秒后解体。硬件冗余,软件不独立,等于没有冗余 |
| DeFi 预言机攻击 | 2020 年的 bZx 等多起事件中,协议只从一个交易所读取价格,攻击者用闪电贷在那个交易所瞬间把价格砸歪,协议据此做出错误清算或借贷。之后行业普遍转向 Chainlink 等多数据源聚合的预言机 |
| 空客电传飞控 | 主飞控计算机由不同团队、用不同处理器和不同软件分别实现,互相监督,就是为了避免阿丽亚娜 5 号式的共模失效 |
区块链钱包里的应用:钱包通过 RPC 节点读取余额、预演交易。如果只用一家 RPC,那家节点出故障、被劫持或者撒谎,钱包就会给用户展示错误的信息。用两家互相独立的 RPC 在同一个区块高度上读取并比对,可以发现这类问题。
Caloogy Wallet 也采用了多源交叉验证。
第三层:原理与工程要点
3.1 怎样才算"独立"
| 看起来独立 | 实际上不独立 |
|---|---|
| 两个不同域名的 API | 背后是同一家云服务商、同一个上游节点 |
| 两个不同的库 | 底层调用同一个依赖 |
| 两台服务器 | 跑同一份代码、读同一个配置 |
| 两个团队 | 照抄同一份参考实现 |
真正的独立意味着:一个出问题的原因,不太可能同时让另一个出同样的问题。
3.2 比对要在"同一时刻"
区块链数据每隔几秒就变。两家节点如果读的是不同区块,结果不一致完全正常。所以要先确定一个区块高度,再让两家都在这个高度上查询。其他系统同理:比较的是同一时刻的快照。
3.3 不一致时怎么办
| 场景 | 处理 |
|---|---|
| 安全相关(是否允许转账、风控结果) | 拒绝并告警(fail-closed,见《Fail-closed》) |
| 展示相关(余额显示) | 显示"数据源暂时不一致",而不是任选一个 |
| 有三个以上来源 | 可以多数表决,但仍要记录和告警少数派 |
3.4 客户端独立复核
一个特别有用的模式:浏览器自己再算一遍。
服务器算出"这笔转账会让你 −100 USDC、对方 +100 USDC",浏览器不直接相信,而是直接连链上节点再算一遍,两者不一致就拒绝。这样即使服务器被攻破、谎报结果,用户看到的关键信息仍然来自浏览器自己的计算。
它的局限也要说清楚:如果页面代码本身被篡改,复核代码会被一起改掉。所以它防的是"服务器被攻破",防不了"前端被攻破"(后者见《Bybit事件与前端完整性》)。
3.5 独立实现的取舍
独立实现(N 版本编程)成本高:两份代码、两套测试、两倍维护。所以只用在最关键、最容易出错的地方,比如:
- 金额和小数位换算(USDC 是 6 位小数,ETH 是 18 位,换算错一位就差一百万倍);
- 收款地址的解析和校验;
- 签名内容的编码。
并且要有专门的测试覆盖两份实现之间的边界情况。
总结
| 层次 | 要点 |
|---|---|
| 原则 | 不依赖单一来源;不一致就停下 |
| 两种冗余 | 多源防"来源撒谎",多实现防"自己的 bug" |
| 独立性 | 原因不同才算独立;阿丽亚娜 5 号是反面教材 |
| 实践 | 同一时刻比对;安全决策 fail-closed;客户端独立复核 |