Skip to content

Lec 21 安全性:拜占庭容错(BFT)

阅读资料:

Practical Byzantine Fault Tolerance(PBFT), OSDI'99

我们到目前为止考虑了很多容错协议,并且总是假设”故障停止“(fail-stop)的失效,比如电源故障。机器会遵守这种这个容错协议,但即便如此,仍然很难处理:需要处理崩溃、网络故障、 网络分区。本节解决的问题比Raft要更难很多,就是找到一种方法能解决更大的一类失效?PBFT 处理拜占庭容错(Byzantine fault),也就是包括恶意节点,在故障时表现为计算错误而不是故障停止;服务器可能不遵守容错协议。

有很多后续工作,PBFT 被作为拜占庭容错的“奠基石”,后续许多协议都建立在它的基础上,比如,

  • Stellar(联邦式 BFT)
  • IBM Hyperledger(企业区块链平台)
  • Tendermint, HotStuff, Zyzzyva 等。

为什么过去不流行? 太贵了:BFT 协议复杂、消息量大,不容易实现和部署。大多数系统选择 预防与检测节点被攻陷(比如加防火墙、签名等)而不是运行 BFT 协议。

为什么又流行起来?区块链带火了共识系统,而共识必须容忍恶意参与者。Bitcoin 通过工作量证明(proof-of-work)和长时间延迟来解决恶意参与者的共识问题 ,但性能差确认慢。PBFT 类协议可提供更快的一致性(尤其适合许可制系统,如企业区块链)。

PBFT的基本思路:使用 状态机复制模型。系统有3f + 1 个副本,其中最多f哥可以是恶意的。只有2f + 1是诚实副本,系统就能形成多数意见并做出正确抉择。使用投票来选出正确的结果。这比看起来要复杂得多。

拜占庭故障的假设

最坏情况:单个攻击者控制 f 个故障副本并试图破坏系统。如果我们能处理这种情况,也就能应对 f 个副本中的漏洞。攻击者的可以采取的手段:

  • 控制故障副本的代码。
  • 知道非故障副本运行的代码。
  • 知道故障副本的加密密钥。
  • 能读取网络消息。
  • 能通过 DoS 暂时延迟消息。

假设不会发生的故障:

  • 超过 f 个副本出错。
  • 客户端没有失败——客户端不做坏事。
  • 无法破解加密密钥或破坏加密。

示例使用场景:

  • RM(修改成绩文件)
    • 写入“echo A > grade”
    • 写入“echo B > grade”
    • 通知 FK“成绩文件已就绪”
  • FK(读取成绩文件)
    • 执行“cat grade”

故障系统可能的行为:

  • 完全编造文件内容。
  • 执行写入"A"操作但忽略写入"B"操作。
  • 显示给 RM 的是"B",但给 FK 的是"A"。
  • 仅在一些副本上执行写入"B"操作。

设计拜占庭容错状态机

设计 1:

  • 1个客户端和 n 个服务器。
  • 假设每个服务器都使用不同的操作系统和服务实现。
  • 一个Client-Server都有公钥对,每个消息都由发送方签名,接收方验证。
  • 客户端发送请求至所有服务器,等待所有 n 个服务器回复,仅当所有 n 个回复一致时才继续。

局限

如果有 1 个恶意节点,它可以故意发送不同回复,或根本不回复,Client就永远等不到一致的恢复。

设计 2

  • 引入副本投票。
  • 2f+1 个服务器,假设最多 f 个是故障的。
  • 客户端等待 f+1 个一致的回复。

局限

f+1 个回复可能来自 f 个坏节点和 1 个好节点,导致客户端被旧的状态误导。

解释

这种设计可能打破线性一致性。看一个操作序列

go
Put(k, "A")     // 所有节点都收到并回复了 A
Put(k, "B")     // g2 没看到;f 和 g1 回复 B
Get(k)          // f 和 g2 回复 A(g2 没看到 B)

结果是 Get 返回 "A" 而不是 "B" 。但这里发生了:

  • Put("B") 是由 f 和 g1 回复的。
    • f 是坏的,可能没真正执行;
    • g1 是唯一诚实节点看到 "B"。
  • Get() 却由 f 和 g2 回复:
    • g2 没看到 "B";
    • f 故意返回旧值 "A"。

image-20250728142614733

设计 3

  • 3f+1 个服务器,最多 f 个是故障的。
  • 客户端等待 2f+1 个一致的回复。

即使有 f 个坏节点,也能确保至少有 f+1 个好节点。因为坏节点最多是 f 个,坏节点不可能单独构造出 2f + 1 个一致的回复。所以,这样可以确保匹配的 2f + 1 个响应中一定有好节点参与。无论哪两个客户端观察到的 2f + 1 个匹配回复集合,而这个重叠节点至少有一个是好节点。

go
Put(k, "A")     // 所有节点(f, g1, g2, g3) 都收到并回复了 A
Put(k, "B")     // f, g1, g2处理了, g3 错过了
Get(k)          // 此时客户端需要等待2f+1=3个副本, 其中f和g3回复A,g1 和 g2 会回复B,客户端不知道如何抉择,但至少能检测到有分歧(即拜占庭行为的迹象)

image-20250728143855769

局限

在单客户端情况下,我们可以靠 quorum(2f + 1) 交集维护一致性。但如果多个客户端并发发请求。 所有副本必须以相同顺序处理操作,才能保证状态一致。这就需要全系统一致的操作排序机制。

我们需要 primary replica(主节点)来排序请求。但是我们需要明白坏主节点能做什么?

  1. 忽略某些客户端请求(拒绝服务)
  2. 给不同副本分发不同操作
  3. 自己算错返回值,或返回老版本的结果

应对坏主节点的思路:

  1. 客户端不仅发请求给 primary,也发送给所有副本

设计 4

  • 客户端将请求发送至主节点和所有副本。
  • 主节点选择下一个操作和操作编号。
  • 客户端在收到 f+1 个匹配的回复时满足。

处理多个客户端的问题

  • 非故障副本必须以相同的顺序处理操作。
  • 将会导致操作执行前需要第三轮消息,即提交阶段

查看更换主节点的方案

  • 每个副本向新主节点发送 2f+1 个最近操作的“准备”消息。
  • 新主节点等待 2f+1 个“视图更换”请求。

如果多于 f 个服务器被破坏,后果是什么?

  • 系统是否还能恢复?

如果客户端被破坏呢?

  • 攻击者可以通过漏洞或密码盗窃攻击一个服务器。
  • 但是为什么攻击者不能控制所有服务器?

论文阅读: 实用拜占庭容错

摘要

本文提出了一种新型的拜占庭容错复制算法。

1. 引言

该算法在不超过总数1/3的副本同时故障时,仍能保证活性与安全性。这意味着客户端最终能收到其请求的响应,且这些响应符合线性一致性要求。该算法适用于互联网等异步系统,并通过关键优化实现了高效运行。

为评估方案,我们开发了复制库并据此实现了真实服务:支持NFS协议的拜占庭容错分布式文件系统。

论文结构如下:第二章阐述系统模型与故障假设;第三章明确算法解决的问题及正确性条件;第四章详述算法设计;第五章介绍关键优化技术;第六章说明复制库的实现及拜占庭容错NFS的构建方法;第七章呈现实验结果;

2. 系统模型

我们假设一个异步分布式系统,其中节点通过网络连接。网络可能出现消息丢失、延迟、重复或乱序等问题。我们采用拜占庭故障模型,即故障节点可能产生任意行为。我们运用密码学技术来防范欺骗攻击和重放攻击,并检测损坏消息。消息中包含公钥签名、消息认证码以及抗碰撞哈希函数生成的消息摘要。节点签名的消息表示为<m>σi,消息m的摘要记为D(m)。我们遵循行业惯例,对消息摘要进行签名后惊奇附加至消息明文。所有副本节点军账务其他节点的公钥以验证签名。

我们假设存在能力极强的攻击者:可协调故障节点、延迟通信或阻滞正常节点,以期对复制服务造成最大损害。但基础假设是攻击者无法无限期阻滞正常节点,同时假定攻击者及其控制的故障节点受计算能力限制,因而(极大概率)无法破解上述密码学技术。例如,攻击者不能伪造正常节点的有效签名、无法从摘要反推原始信息、也不能找到具有相同摘要的两个不同消息。

3. 服务特性

我们的算法可用于实现任何具有状态和若干操作的确定性复制服务。

4. 容错算法

我们的算法属于状态机复制的一种形式:将服务建模为在分布式系统中多个节点间复制的状态机。每个状态机副本均维护服务状态并实现服务操作。我们用集合R表示所有副本,并为每个副本分配0到|R|-1的整数标识。为简化起见,我们假设|R|=3f+1,其中f为可能发生故障的最大副本数;虽然可以配置超过3f+1个副本,但额外副本会降低性能(因为需要交换更多更庞大的消息),且无法提升容错能力。

副本通过一系列称为视图的配置进行状态演进。在每个视图中,一个副本担任主节点,其他副本作为备份节点。视图按连续整数编号。视图 v 的主节点为副本p,满足 p = v mod |R|。当主节点疑是故障时,系统会执行视图切换。视图v的主节点为副本p,满足p = v mod |R|。当主节点疑似故障时,系统会执行视图切换。Viewstamped复制[26]和Paxos[18]也采用类似方法处理良性故障。

算法基本工作流程如下:

  1. 客户端向主节点发送调用服务操作的请求
  2. 主节点将请求组播至备份节点
  3. 所有副本执行请求并向客户端返回响应
  4. 客户端等待接收来自不同副本的f+1个相同结果,该结果即为操作最终结果

与所有状态机复制技术[34]相同,我们对副本提出两项要求:必须具有确定性(即在给定状态和参数下执行操作必须始终产生相同结果),且必须从相同初始状态启动。满足这两项要求后,本算法通过保证所有非故障副本就请求执行的全序达成共识,从而确保安全性特性。

本节剩余部分将描述算法的简化版本。由于篇幅所限,我们省略了节点故障恢复机制的讨论,同时略去与消息重传相关的细节。此外,我们假设采用数字签名而非基于消息认证码的更高效方案实现消息认证;第5节将对此进行进一步探讨。基于I/O自动机模型[21]的完整算法形式化描述详见文献[4]