防御性协议设计

sigmaprime 发布于 2026-03-03 阅读 160

本文深入探讨了DeFi协议的安全设计策略,强调防御性设计的重要性。

在设计新协议时,很容易过于关注设计目标以及 dApp 如何让用户执行操作。然而,与普通应用不同,dApp 必须更加重视安全性,因为用户资金的安全取决于开发者的设计决策。

最近 Balancer Finance 被利用以及 Stream Finance 的崩盘,使这个问题成为了讨论焦点。前者是由于池核算中的四舍五入错误,尽管经过了多次审计、提供了可观的漏洞赏金并且拥有经验丰富的开发团队。而后者则是由于基金经理的风险管理疏忽。原因截然不同,但两者都凸显了防御性协议设计的必要性。

在本文中,我们将讨论类似 Balancer 的情况,探讨开发者可以采用哪些选项来大幅降低在智能合约中出现严重漏洞的可能性,并在漏洞被利用时降低其严重性。

断路器与机器人:自动化或手动

首先,在设计 dApp 时,值得花时间考虑系统中可能出现的情况。然后,这些情况可用于对协议内的可接受范围添加限制。一个常见的例子是借贷市场,如果某种资产的市场平均利率约为每年 5%,而在单笔交易内突然上升到 90%,这极不可能是一笔合法交易。可以在合约中编写断路器以防止此类交易发生,这些断路器不太可能限制普通用户,但能为防止利用提供有用的障碍。

由于此逻辑是公开可访问的,恶意行为者可能会试图通过将利用拆分为多笔接近但不超出断路器值的交易来绕过这些对策。这时,手动断路器就能发挥作用:协议还可以有一个链下机器人,寻找异常活动,并在检测到异常时暂停协议。链下解决方案的优势在于触发条件可以保密,从而减少攻击者可利用的信息。自动条件暂停能在区块链拥堵时对市场状况做出更快反应,但开发者必须对功能进行压力测试,以确保在非典型 Gas 条件和 RPC/API 响应时间下也能持续运行。

机器人故障的一个例子是由 Maker DAO 编写的参考拍卖客户端,旨在对 DAI 抵押债仓出价以清算资不抵债的贷款。该拍卖机器人在典型 Gas 条件下运行顺畅,但未能充分编程以应对 2020 年 3 月 12 日经历的 Gas 拥堵。这导致所有拍卖机器人实例未能对活跃拍卖出价,其他行为者能够在不提供典型还款金额的情况下索取违约贷款抵押品。可以通过允许链下机器人的动态 Gas 限制、使用重试策略检测失败或停滞的交易,以及开发多个客户端来执行操作,从而避免此类情况。

断路器的一个潜在缺点是,如果过于敏感,可能会在真实用户交易中触发,导致使用 dApp 时产生挫败感。但通过仔细微调,可以减少此类情况的发生。

Compound Finance 是一个抵押借贷协议,使用断路器来应对最近的威胁。其平台受到了 Stream Finance 崩溃引发的冲击波影响。他们启用了对 Elixir Finance 的 deUSD 和 sdeUSD 代币的借贷,已知这些代币对 Stream Finance 有一定敞口,并因此出现了脱锚。Compound 的风险咨询机构 Gauntlet 提议冻结对其他稳定币的进一步借贷,直到可以对协议进行更新,以防止用户以 deUSD/sdeUSD 为抵押进行借贷。冻结进一步借贷阻止了 deUSD/sdeUSD 持有者从 Compound 抽取可用资金,并将坏账转嫁给其他 Compound Finance 用户。

缓慢扩展与资产供应上限

限制损失的一个简单机制是初始时减少协议管理的资产价值。可以通过利用 Beta 测试以及在后续部署中使用资产上限来实现,例如借贷项目可能限制可供应或借入的资产数量。

如果测试网部署配合积极的安全措施,如漏洞赏金和进一步审计,这可以让项目在使用真实资金部署合约之前发现问题。

一旦部署,项目可以通过引入资产存款最大值来缓慢扩展。这可以增强对系统设计的信心,并最小化黑客攻击的影响,使项目更有可能恢复和重新启动。如果处理得当,此类限制可以激发兴趣,因为如果经济激励良好,用户可能会争相参与。

一个例子是 Abracadabra.money,一个跨链 DeFi 借贷平台,在 2025 年 10 月遭到黑客攻击。攻击目标是六个已弃用的借贷合约,导致 180 万美元的 MIM 代币损失。虽然这是一个惨痛的教训,但由于对受影响的合约使用了借贷限制,该协议得以避免彻底毁灭。DAO 随后能够使用国库资金弥补损失,防止黑客进一步影响其他持有流通中 4300 万美元 MIM 的用户。

合约内外的异常事件追踪

与使用链下断路器类似,项目监控日常使用情况非常有用,因为并非所有漏洞都是即时性的单笔交易。通过积累协议接收的平均交易数量和类型的知识,可以构建模型,标记异常供开发者进一步审查。通过观察这些数据,开发者还可以基于实际使用情况检测到非预期的设计异常,并在被利用之前纠正问题。

YieldBasis 是一个基于 Curve Finance 的 crvUSD 稳定币构建的波动性代币流动性提供协议,他们正在广泛使用性能分析来追踪其已部署池的预期表现。虽然可以设计公式并预测性能,但由于市场动态,市场的许多其他方面难以准确预测。不断上涨的 Gas 费用会影响套利者快速交易的能力,而对于 YieldBasis 来说,这是其资产再平衡过程的核心假设。在推出其池后,他们注意到 2025 年 10 月 10 日的价格暴跌给流动性提供者带来了一些无常损失。

在讨论其表现时,YieldBasis 指出,增加流动性将通过增加套利收益并在市场 Gas 价格高时激励平衡交易来减少池收益的波动性。YieldBasis 通过将每个池的上限从 2000 万美元提高到 5000 万美元,并赞助 crvUSD 池中的合作伙伴流动性,以实现更高效的兑换路径。

最小权限原则/基于角色的访问控制

即使协议背后的经济理论是严谨的,由于治理设计松懈,项目也可能自食其果。虽然通过治理和代理设计实现可变性可能很诱人,但这也可能成为一种威胁。Liquity,一个 DeFi 超额抵押借贷协议,选择为其稳定币 LUSD 和 BOLD 部署不可变合约,因此在希望在 DeFi 中运营时最小化攻击向量的用户中获得了青睐。LUSD 或 BOLD 稳定币的用户可以更安全地知道协议团队无法禁用或更改系统设计。

当确定需要特权角色时,角色应具有细粒度的访问权限,并在不同账户之间拆分,以在某个角色账户被外部方或前成员攻破时减少影响。

在讨论断路器时,我们提到了可以暂停合约功能的链下机器人。这是利用角色访问来提供额外安全功能而不危及用户资产的一个例子。由于此类机器人角色必须自动化,它们比更安全的参与者(如硬件钱包或多重签名)更容易被劫持。因此,它们充分利用“最小权限”概念大有裨益。在此概念下,它们可以被阻止访问其他管理员功能,同时保持对暂停合约的快速响应时间。

此概念应应用于协议内具有角色的所有参与者,以防止账户接管或恶意员工相关风险。一个本可以通过更好的角色控制来避免的例子是 Pump.fun 的资金被抽干,这是一个由心怀不满的员工发起的 memecoin 发射平台攻击。该前员工利用对协议私钥的特权访问,使用仅限管理员的功能窃取用户资金。

多重签名钱包与模拟

如果开发团队专门使用多签账户,Pump.fun 的这次攻击本可以避免。多签是一种专门的智能合约,需要多个外部拥有账户的签名才能执行交易。协议中的非自动化角色应由强大的多签智能合约操作,并配备独特、响应迅速的签名者,以使攻破管理员角色变得极其困难。

虽然更难攻破,但多签账户只是第一步。像 Bybit 前端欺骗 这样的攻击,导致交易所从其多签钱包损失了 14 亿美元,凸显了在国库账户管理中需要主动的层次化防御。必须使用外部工具,如 TenderlyOpenZeppelin 的 Safe Utils 以及使用 Forge 等工具集的本地测试网来模拟交易并验证协议升级或交易将按预期进行。

虽然开发团队位于协议之外,但考虑个人操作安全措施至关重要,尤其是在它们与协议安全交叉时。Bybit 攻击源于另一家公司 Safe Wallet(Bybit 使用的多签平台)一位开发者的开发系统遭到破坏。随着智能合约开发者越来越习惯更好的设计实践,行业看到更多的间接攻击正在蔓延。例如,攻破开发者系统以获取私钥或前端管理系统。

开发者应对第三方联系保持谨慎,对下载软件犹豫不决,并通过仔细的版本控制保护开发依赖项。建议使用气隙隔离的开发系统,并且在安装常见开发工具的插件时必须小心,以确保使用正确的插件,而不是仿冒或双胞胎插件。一个快速的启发式方法是检查插件的发布日期。通常,假插件会被报告并移除,防止长期存在,但仍需谨慎,因为这无法保护免受被劫持的插件攻击。

关于 DAO 治理的其他需要注意的问题,请参阅我们的上一篇文章

设计期间的 worst-case 建模

协议设计周期的一部分应包括推测机制可能如何出错以及 worst-case 情景会是什么样子。这个过程有助于引导协议安全设计,并且对于告知未来的审计方(项目可能与之合作)哪些风险已被预料以及开发者采用了何种思维方式也非常有用。

项目应审视预期的协议操作,并理论化什么会构成系统故障,包括严重故障和更温和的故障(如临时拒绝服务)。研究过去的黑天鹅事件以及受影响的协议在这些事件中具体如何遭受损失,有助于威胁建模。

一旦完成此过程,就可以采取措施来减少此类故障的影响,如下所述。

防御性代码设计

随着智能合约攻击模式的发展,出现了针对常见攻击方法的特定策略。大多数开发者都熟悉重入攻击及其由此产生的重入锁的使用,以防止同一交易内的多次函数调用。

前面提到的链上断路器也是防御性代码设计的另一个例子。 可以应用的其他策略包括阻止在同一交易中执行多个协议操作。虽然与重入锁类似,但这采用了更宽松的常识性方法:普通用户不太可能先执行一个操作,然后在同一交互中撤销它。

例如,在同一个交易中先存入借贷市场或DEX,然后取出。使用此机制必须深思熟虑。在后一个例子中,高级真实用户可能试图因一笔特别大的交易而提供短暂的“即时”流动性到 DEX 交易对。不允许此类操作可能会对交易者的有效价格产生负面影响,损害真实用例。防御性设计需要合理,并注意可能阻止的利基真实应用。

另一种防御性设计方法是将用户资产隔离到不同的合约中,或者如果资产是集中池化的,则应在每次调用结束时完成严格的会计核算检查,以确保余额仅按预期方式发生变化。借贷协议 Gearbox 通过合约生成事件实现了用户隔离,并通过空投激励参与者。这些合约随后形成孤立的借贷账户,可以重新分配给不同的用户,并允许彼此隔离的复杂借贷活动,降低了系统性破产风险。

另一个常见的考虑是确保智能钱包可以使用 dApp。一个常见的陷阱是试图强制调用者为 EOA,假设只有智能合约才会恶意调用你的协议。这个假设是有缺陷且限制性的,而且实现这一目标的典型机制可能不合适。一种典型方法是确保 msg.sender == tx.origin,因为这曾经是确保调用者为 EOA 的机制,然而,随着 Pectra 更新的引入,由于账户抽象,这一假设不再成立。

纵深防御

不正确的安全假设,例如上述检测消息发送者,可能会使对协议设计安全至关重要的安全假设失效。虽然创建关于项目的不变量有助于推理可达操作的状态空间,但最好按照顺序使用多种防御措施,这样如果一种措施失效,其他措施仍能发挥作用。

一个常见的例子是不使用稳定币的预言机,因为其价值通常应为 1 美元,并将此值硬编码。虽然通常如此,但如果这一假设不成立,可能会产生灾难性后果。因此,在协议中设计多重检查非常重要,这样如果某个不变量被证明不成立,其他流程可以继续保护系统。

例如,可以从多个来源生成价格预言机。这样,如果某个来源变得不准确,系统可以设计为丢弃其影响,例如使用中位数预言机值。

其他防御性设计决策,例如重入锁,可以融入此概念。虽然开发者可能无法预见到由重入引起的漏洞,但如果发现某个函数可能导致此类操纵,可以使用这些锁来阻止此类情况的发生。

Liquity 开发的 BOLD 稳定币在其抵押品预言机设计中使用了纵深防御。该协议支持流动性质押代币 stETH 和 rETH 以及原生 ETH 作为抵押品。这些代币使用 Chainlink 价格源定价,同时关注上次价格更新的时间戳。如果价格变得陈旧,则该抵押品分支进入关闭模式,阻止进一步的借贷发生,同时仍然允许可以降低用户债务的操作。这有助于在预言机停机时防止协议攻击。

高级测试与审计

完成这些过程后,协议应通过单元测试和集成测试广泛内部测试其协议行为。如果时间允许,还应探索模糊测试和不变量分析。单元测试允许快速验证增量代码库更改是否改变了预期行为,而集成测试则确保可能包含其他协议的端到端操作按预期执行。

模糊测试和不变量测试允许进行更复杂的测试,可能会发现手动审查或单元测试难以想象的边界情况。虽然此类边界情况在典型使用中可能不会发生,但发现它们很有价值,因为攻击者通常会操纵协议状态进入不变量不再成立的异常状态。

之后,团队应寻求由审计方审查其代码,根据代码库规模留出足够时间,并且最好考虑由不同的审计公司依次进行多次审计。

漏洞赏金与清晰的安全沟通渠道

最后,如果所有其他措施都失败,建立有效的联系方法至关重要,并且如果可能,为白帽黑客负责任地披露漏洞提供奖励。协议应寻求与赏金平台(如 Immunefi)合作,并提供公平的奖励,反映所防止的损害成本。此类安全联系方法应易于访问,并在所有部署在链上的代码中注释。最好提供多种联系方法,例如专门的安全电子邮件以及其他低摩擦和匿名的联系方式,旨在尽可能降低报告问题的障碍。

团队应建立一个由负责任的团队成员组成的框架,可以联系他们报告问题,并测试其响应解决协议,以确保如果发生真实问题,他们已做好充分准备来应对。

消防演习能救命

即使采取了所有这些预防措施,利用仍然可能发生,因此协议应建立可在最坏情况发生时的应对框架。这应包括内部信息(如联系谁)、关于如何冻结系统所有方面的清晰说明,以及有用第三方联系人的详细信息,如 SEAL 911。

团队应维护一个与协议集成的代币和服务相关的联系人目录,并记录每个利益相关者可以采取的措施,但由于各方响应可能反复无常,这应严格作为备份。虽然某些代币或链有能力冻结账户或防止被黑资金移动,但由于干预可能带来的法律影响,它们通常不愿这样做。

一旦威胁得到控制,系统不应重新上线,直到完全理解漏洞的根本原因并缓解,否则协议可能会面临模仿攻击,就像 Compound 所经历的 COMP 铸造错误一样。

此问题发生在过多的 COMP 治理代币被铸造时。一些用户注意到这种过剩,并通过精心构造的交易调用窃取了这些代币。Compound 做出反应并触发了必要的更改以阻止进一步损失,但由于其治理合约为了保护现有用户而强制执行的时间延迟,他们只能眼睁睁地看着其他用户随后复制利用交易来免费申领额外代币。

修复实施后,总抽干资金达到 1.47 亿美元,尽管一些领取者后来将资金返还给了 Compound 治理地址。

结论

值得记住的是,利用带来的风险不仅限于资金本身,通常,在重大黑客事件中幸存的协议可能发现很难吸引新用户、重新获得市场信心或找到新投资者。如果团队理解并实施了本文中提到的保护措施,他们的协议将更有可能取得长期成功。用于保护每个协议的方法将因其设计而异。虽然协议应防范边界情况,但它们也必须谨慎,确保保护措施不会锁定真实客户资金。

  • 原文链接: blog.sigmaprime.io/defen...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~

相关文章

0 条评论