12种智能合约漏洞及如何缓解
随着智能合约越来越多地用于保护数字资产,开发者面临着各种安全威胁。最近的高调攻击事件——包括Penpie损失2700万美元和Cetus被黑客攻击2.23亿美元——凸显了正确编码以防止漏洞的重要性。
智能合约在满足特定事件、条件和逻辑时执行流程、交易和其他任务,具体取决于它们的编程方式。它们部署在区块链上,如以太坊或其他分布式账本基础设施,在那里监听来自加密安全数据源(称为预言机)的事件和更新。
金融、医疗保健和保险等许多行业使用智能合约来控制大量有价值数据和资源的流动,例如转账、提供服务和解锁受保护内容。这自然使它们成为恶意行为者的有吸引力的目标。
在设计和开发智能合约时,安全必须是首要任务。一旦智能合约部署到区块链上,就很难或不可能修补;必须将其删除、重新创建和重新部署。此外,一旦智能合约在区块链上,任何人都可以访问其中的漏洞。
在流行的智能合约平台以太坊上部署用Solidity编写的智能合约时,开发团队需要特别了解以下攻击向量以及如何消除它们。
1. 重入攻击
重入攻击向量存在是因为Solidity智能合约是强制性执行的:每行代码必须在下一条开始之前执行。这意味着当合约向不同合约进行外部调用时,调用合约的执行将暂停,直到调用返回。这实际上让被调用合约临时控制接下来发生的事情,创造了无限循环的可能性。
例如,恶意合约可以递归调用回原始合约以提取资源,而无需等待第一次调用完成,因此原始合约在函数完成前永远无法更新其余额。重入攻击的形式包括单函数、跨函数、跨合约、跨链和只读。GitHub维护了一个漏洞利用列表。
修复:当智能合约的代码逻辑存在缺陷时会发生此漏洞。开发者需要仔细设计外部调用,并始终检查和更新合约状态,例如在完成发送资金的请求之前减少以太币余额。添加重入防护可以通过锁定合约来防止多个函数同时执行。各种审计工具,如Slither和Securify,可以检查是否存在不同类型的重入漏洞。
示例:在2024年对Penpie去中心化金融(DeFi)协议的重入攻击中,攻击者窃取了价值2700万美元的以太币,这是以太坊的原生加密货币。
2. 预言机操纵和闪电贷攻击
智能合约使用预言机访问和消费来自区块链外部的数据。这让它们能够与链下系统(如股票市场)交互。不正确或被操纵的预言机数据可能错误地触发智能合约的执行;这被称为预言机问题。
许多DeFi应用程序都使用这种方法被利用,最受欢迎的是闪电贷攻击。闪电贷本质上是无抵押贷款,只要在同一交易中偿还贷款,借款金额没有限制。攻击者使用这些贷款扭曲资产价格以产生利润,同时仍然遵守区块链的规则。
修复:使用去中心化预言机,如Chainlink或Tellor——甚至多个预言机——是确保合约接收准确数据的最简单方法。这样的预言机使攻击者干扰数据变得更加困难和昂贵。
示例:Abracadabra去中心化加密资产借贷平台经历了一次闪电贷漏洞利用,攻击者窃取了约1300万美元的以太币。
3. 不安全随机性
加密算法在生成密钥和执行智能合约的其他操作时依赖随机数源。密码学的一个基本原则是随机数必须不可预测,虽然这听起来很明显,但实现起来通常相当具有挑战性。如果随机性源不强,并且它们生成的值有任何可预测性,这可能为攻击提供几个机会来规避对智能合约完整性至关重要的加密保护。
修复:仅使用基于公认标准的随机数生成加密技术。NIST有一个完整的研究项目和一套专注于随机数生成的标准。
示例:$FFIST加密货币代币遭受了一次攻击,导致损失约11万美元。该攻击可追溯到可预测的随机性源。
4. 业务逻辑错误
业务逻辑错误是智能合约内部或智能合约之间的设计错误的总称。设计错误导致合约的行为与预期行为不同。攻击者可以利用业务逻辑错误来操纵合约并窃取资金。
修复:开发者应彻底测试所有合约代码,包括所有业务逻辑组合,并验证观察到的行为在每种情况下都与预期行为完全匹配。考虑使用手动和/或自动化流程和工具来分析合约代码中可能的业务逻辑错误。
示例:SIR.trading DeFi协议在2025年3月经历了一次逻辑缺陷攻击,导致约35.5万美元被盗。
5. 强制喂送攻击
强制喂送攻击利用了开发者无法阻止智能合约接收以太币的事实。这使得向任何合约转移以太币变得容易——强制喂送它——以改变其持有的以太币余额,从而操纵任何仅依赖预期余额进行内部核算的函数逻辑,例如如果余额增加到某个水平以上则支付奖励。
修复:无法以这种方式阻止合约余额操纵。永远不要使用合约余额作为函数内的检查或防护,因为实际以太币余额可能高于合约内部代码预期的余额。
6. 缺乏输入验证
所有软件都需要验证输入;这几十年来一直是软件开发的核心原则。软件开发者假设所有软件输入都将如预期那样是危险的。攻击者可以制作导致崩溃的输入,可能暂时中断对智能合约的访问,或者导致软件以意外方式运行。更令人担忧的是使用输入来改变数据或更改软件本身,这两者都可用于操纵智能合约。
修复:开发者应确保所有输入在使用前都经过仔细验证,确保完全符合预期。在合约中添加双重检查,以防意外输入以某种方式通过验证并被处理。有关更多信息,请参阅Solidity文档中的错误处理部分。
示例:Onyx DeFi协议在输入验证漏洞遭受攻击后面临380万美元的损失。
7. 拒绝服务
与任何在线服务一样,智能合约容易受到DoS攻击。通过过载服务(如身份验证),攻击者可以阻止其他合约执行或生成意外的合约回滚,例如,未使用的gas被返回,所有状态恢复到交易开始执行前的状态。这可能导致拍卖结果或金融交易中使用的值被操纵以利于攻击者。
修复:使这些攻击对攻击者来说成本高昂是阻止他们的最佳方式。时间锁谜题和gas费用只是增加攻击者成本的一些方式。确保仅向受信任的合约进行调用也降低了DoS攻击导致严重问题的可能性。
示例:这不是攻击的示例,但在2025年4月,以太坊改进提案7907升级获得批准,以帮助防止合约通过gas计量成为DoS攻击的受害者。
8. 整数下溢和上溢
当算术运算的结果落在固定大小值范围之外时,会发生整数下溢和上溢:对于整数类型uint8,范围为零到255。高于255的值上溢并重置为零,而低于零的值重置为255。这会导致合约状态变量和逻辑发生意外变化,触发无效操作。
修复:自2020年底发布0.8.0版本以来,Solidity编译器不再允许可能导致整数下溢和上溢的代码。检查任何使用早期版本编译的涉及算术运算函数的合约,或使用库(如SafeMath)检查下溢和上溢问题。
示例:2025年5月Cetus去中心化交易所黑客攻击,造成估计2.23亿美元的损失,是代码溢出检查遗漏的结果。
9. 访问控制漏洞
任何人都可以访问区块链。除非加密,否则切勿将机密或敏感信息保存到区块链。智能合约中的状态变量和函数也可能对其他智能合约可见和可访问,这使得它们可能被误用或滥用。
修复:开发者应始终按照最小权限原则实施适当的访问控制,使用Solidity的状态变量和函数可见性说明符分配必要的最低可见性级别,且不超过必要级别。
示例:KiloEx去中心化交易所由于智能合约中缺乏访问控制而遭受约700万美元的损失。
10. Gas困扰
要在以太坊区块链平台上执行交易或执行智能合约,用户必须支付gas费。支付gas费是为了激励验证者(矿工)投入验证交易所需的资源。gas的价格由交易时的供应、需求和网络容量决定。
当用户发送执行目标智能合约所需的gas量但不足以执行子调用——它向其他合约发出的调用时,会发生gas困扰。如果合约不检查执行子调用所需的gas是否可用,子调用将不会按预期执行。这可能对应用程序的逻辑产生重大影响。
修复:不存在防止gas困扰的有效技术。开发者应编码合约,使其设置要发送的gas量,而不是由用户设置。然而,gas成本的上升可能意味着交易失败。
11. 交易顺序依赖攻击(抢先交易)
智能合约从作为待处理交易提交到网络的那一刻起就是公开可见的。这使得区块矿工可以选择具有最高gas费用的交易。例如,用户可以包含优先费——小费——以激励矿工将他们的交易优先于同一区块中的其他交易。然而,这也使攻击者能够观察机会,通过提交相同的合约但具有更高的gas费来抢先运行有利可图的合约,以便他们的合约首先被处理。由于这些攻击必须在几分之一秒内实施,它们通常由机器人或矿工自己执行。
修复:这些攻击很难避免。一种选择是仅接受gas价格低于预定阈值的交易。或者,使用提交和揭示方案,涉及用户首先提交解决方案哈希而不是明文解决方案,以便潜在抢先者在为时已晚之前无法查看它。各种智能合约审计工具可以检测代码是否引入抢先交易漏洞。
12. 时间戳依赖
执行智能合约的节点生成时间戳值。由于以太坊平台的分布式性质,几乎不可能保证每个节点上的时间正确同步。然后,节点可以操纵其使用的时间戳值,以针对任何依赖block.timestamp变量执行时间关键操作的合约进行逻辑攻击。
修复:为避免此漏洞,开发者不应使用block.timestamp函数作为控制或逻辑检查,或作为随机性源。
保持智能合约无漏洞
为了让智能合约变得智能和安全,开发团队必须从一开始就内置安全性,并严格测试其逻辑和代码执行。
合约代码在部署后很难修补。第一次就确保安全是必要的。始终遵循智能合约安全最佳实践。除非开发团队包括专门的智能合约安全专家,他们可以通过单元测试每个函数来审计智能合约代码的逻辑缺陷和其他漏洞,否则请使用专门从事智能合约的审计服务来识别任何安全问题。