通过链上速率限制器缓解跨链桥攻击

起因

近期,发生了几起非常严重的跨链桥黑客事件,造成了重大损失:

  • 2022 年 2 月 2 日,Wormhole 遭到攻击,损失 3.2 亿美元;

  • 2022 年 3 月 29 日,Ronin 遭到攻击,损失超过 6 亿美元。

这些损失引发了一个关于异构链互操作性安全级别方面的长远思考,尤其集中在如何能够减少或缓解这些攻击的方面。实际上,所有这些攻击都源于一个跨链预言机问题——如何确保某些事件(例如,锁定/销毁事件)在源链上发生,以避免发生下列情况:

  • API故障:如Wormhole所经历,黑客利用一些已弃用而Wormhole仍信任的 API进行攻击;或者

  • 密钥被盗:正如 Ronin 所经历的,黑客获取了 9 个验证者密钥中的 5 个。

当 API 被利用或密钥被盗时,黑客可以在目标链(尤其是去中心化程度比较高的以太坊 等)上提交一个取走全部交易的指令转走所有链上资产,即便源链上没有相应的锁定/烧毁事件。尽管跨链桥可能在几个小时后检测到这种异常活动,然而资产已经转移到黑客的账户中,并且很难追回。

通过速率限制器缓解攻击

速率限制器是一种确保稀缺资源在特定时间内不被滥用的通用技术。例如,通过将服务器的访问限制设置为每秒 100 万个请求,我们可以防止服务器被 DDoS 攻击的大量流量冲垮。

运用到跨链桥场景,速率限制器的基本思想是如果每天的提款金额超过预设限制(例如,2000 万美元),则暂停提款。此外,速率限制器将通知跨链桥的项目方,并进行人工干预以检查跨链桥的安全状况。如果一切正常,可以重置一天的限额来再次进行提款。注意,速率限制也是 CEX 的常用安全措施。

速率限制器能够缓解攻击造成的损失,尤其是对这种一次取走全部资产的攻击。例如,假设我们将桥的提现额限制为每天 2000 万美元,那么攻击者一天最多只能进行 2000 万美元额度的攻击。也就是说,如果跨链桥的项目方可以在一天内发现遭到了攻击,就可以将跨链桥总锁仓的损失减少到仅为每天限额值(例如,在 Ronin 案例中,仅损失 2000 万美元而非 6 亿美元)。

速率限制器类型

链下速率限制器

在公证/多签场景中,链下速率限制器可能是最简单的实现方式。中继/共同签名者将实现一个链下算法(实际上 QuarkChain 桥也实现了这部分),如果超额,他们将拒绝签署交易到目标链。他们可能会进一步要求人工干预以确认跨链桥的健康状态,然后再重置限额并继续工作。

链下速率限制器的优势在于非常高效——不需要更改链上合约,也无链上 GAS 成本。此外,链下速率限制器可以减轻 API攻击的情况(如 Wormhole ),一旦请求 3 亿美元的提款,多签节点将停止签名。其结果是,黑客只能请求一个比3亿美元小得多的提款金额,最多只能窃取 2000 万美元(因为限额)。

链下速率限制器的缺点是它无法缓解密钥被盗的情况。因为一旦密钥被盗,黑客可以通过直接对提款交易进行签名来绕过多签部分。这意味着对Ronin的攻击仍可发生。

链上速率限制器

我们可以采用链上速率限制的方式来减轻多签秘钥被盗的损失,但会以额外的链上 GAS 消耗为代价。除非金额小于允许的限额,否则即使黑客用秘钥签署了提款交易,链上合约也会阻止此类提款。这为项目方提供了额外的时间(例如 24 小时)来检测攻击并在发现时停止跨链桥。

一个关键问题是如何以高效使用 GAS 的方式实施限额合约。Consensys 提供了一个速率限制器的版本

https://consensys.github.io/smart-contract-best-practices/development-recommendations/precautions/rate-limiting/。Consensys 版本的基本理念是将时间划分为不重叠的时间段,每个时间段有一个最大提取金额。

通过链上速率限制器缓解跨链桥攻击

双倍限额攻击示意图

虽然 Consensys 速率限制器比链下更安全,但通过执行以下策略,可以造成2倍限额的损失(例如,假设限制是 2000 万美元,但攻击最多可以窃取 4000 万美元) :

  • 在一个时间段的最后操作一次提款;

  • 在下一个时间段开始时再进行一次提款。

如果两次提款的间隔很小,那么跨链桥的项目方可能没有足够的时间来检测第一次的提款攻击,并停止下一次提款。

基于滑动窗口的链上速率限制器

对于 Consensys 的实现而言,其问题在于速率限制时间段的粒度太大(例如,24 小时)。我们可以在多个速率计算的时间单位(bin)上使用滑动窗口的方式来获得更小的粒度:

  • 每个 bin 定义了一个更细粒度的时间间隔(例如,1 小时);

  • 每个 bin 用来累计在该bin定义的时间的取款数目;

  • 取款的速率可以通过添加最近的 bin 的数目来产生(例如,24小时24个包);

  • 过期的 bin 可以重复使用以节省存储成本(以及GAS 成本 )。

下图说明了有滑动窗口的链上速率限制器的基本思想(以每个 bin 6小时为例)。

通过链上速率限制器缓解跨链桥攻击

滑动窗口速率限制器示意图

滑动窗口速率限制器的优势在于,攻击者现在必须等待速率限制的持续时间减去bin 持续时间才能提交下一个攻击交易。如果以 24 小时作为限速持续时间,1 小时作为 bin 持续时间,我们可以将下一次攻击推迟到 23 小时后,并且希望跨链桥能够在 23 小时内检测到第一次攻击并停止工作。

基于智能合约的高效实现

我们在这里 https://github.com/quarkchain/rate-limiting 实现了一个高度优化的滑动窗口限额的实现(请注意,代码未经审计,因此使用风险自负)。平均 gas 成本约为 20k,小于 Ronin 提款交易(约 230k gas)的 10%。主要优化部分是在存储上,我们在其中使用了压缩的 bin 表示,以便最大限度地减少 sload/sstore 操作码的使用。

结论

在本文中,我们提出了一种带有滑动窗口的速率限制器,以减轻跨链桥的攻击损失。此外,我们还提供了一种高效且低gas成本的实现方式。我们相信速率限制器的思想和实现可以大大降低跨链互操作协议的风险。