福利加码,Gate 广场明星带单交易员三期招募开启!
入驻发帖 · 瓜分$30,000月度奖池 & 千万级流量扶持!
如何参与:
1️⃣ 报名成为跟单交易员:https://www.gate.com/copytrading/lead-trader-registration/futures
2️⃣ 报名活动:https://www.gate.com/questionnaire/7355
3️⃣ 入驻Gate广场,持续发布交易相关原创内容
丰厚奖励等你拿:
首发优质内容即得$30 跟单体验金
每双周瓜分$10,000U内容奖池
Top 10交易员额外瓜分$20,000U登榜奖池
精选帖推流、首页推荐、周度明星交易员曝光
详情:https://www.gate.com/announcements/article/50291
深入了解重入攻击及有效防护方法
重入攻击是智能合约中最严重的安全威胁之一。本文将不仅介绍重入攻击的工作原理,还将全面指导你如何保护你的项目。
为了全面理解,我们将从基础概念开始,分析实际攻击的源代码,最后探索三种经过验证的防御技术:从 modifier nonReentrant() 到 GlobalReentrancyGuard() 以及“检查-效果-交互”模式。
什么是重入攻击?
想象两个智能合约相互交互。ContractA 和 ContractB 完全可以相互调用。这看似正常,但实际上这是攻击者可以利用的漏洞。
重入的核心概念是:一个智能合约可以在另一个合约仍在执行时,反向调用该合约。这会形成无限循环,除非被正确控制。
举例说明:ContractA 持有 10 Ether,其中 ContractB 已经向其发送了 1 Ether。正常情况下,当 ContractB请求提款时,会检查(余额 > 0),然后转账 Ether,最后将余额设为 0。但在重入攻击中,这个过程可以在余额更新之前反复执行多次。
重入攻击的工作机制
攻击者需要两个主要部分:一个 attack() 函数和一个 fallback() 函数。
fallback 是 Solidity 中的特殊函数——没有名字、没有参数、没有返回值。当满足以下条件时会自动触发:
攻击流程如下: 步骤1: 攻击者调用 attack(),在其中调用 ContractA 的提款函数。
步骤2: ContractA 检查余额(大于0),然后转账 1 Ether 给 ContractB,并触发 fallback。
步骤3: 关键点——余额尚未更新,仍为原值。
步骤4: fallback 被触发,立即反向调用 ContractA 的提款函数。
步骤5: ContractA 再次检查余额(仍大于0),再次转账 1 Ether,触发 fallback。
此过程不断重复,直到 ContractA 的 Ether 被全部转出。这就是重入攻击的危险所在。
具体攻击代码分析
以 EtherStore 合约为例,它有两个主要函数:
withdrawAll() 的流程:检查余额(>0)、转账 Ether、将余额设为0。
漏洞在于:转账发生在余额更新之前,攻击者可以在转账过程中反复调用。
攻击合约 Attack 设计如下:
攻击步骤:
三种防御重入攻击的技术
技术一:使用 modifier nonReentrant
最简单的保护单个函数的方法是用 nonReentrant 修饰符。它在函数开始时锁定合约,防止在执行过程中再次调用。
工作原理:
缺点:
技术二:检查-效果-交互(Check-Effect-Interaction)
更精细的防护方式。通过调整代码执行顺序:
示例:
这样即使发生重入,余额已被更新,不会被重复利用。
技术三:GlobalReentrancyGuard(全局重入保护)
适用于多个合约交互复杂的项目。创建一个中心控制的合约,用于全局检测重入。
原理:
例如:在 ScheduledTransfer 和 AttackTransfer 之间的交互中,GlobalReentrancyGuard 能有效阻止攻击。
选择合适的防御技术
使用 nonReentrant:
使用 Check-Effect-Interaction:
使用 GlobalReentrancyGuard:
结合使用这些技术,依据项目具体需求灵活选择。
结论
重入攻击并非不可防范。只要理解其机制,合理应用防御技术,就能有效保护智能合约。从简单的 modifier 到全面的全局保护,每种工具都在安全体系中扮演重要角色。
安全不是选择,而是责任。理解重入攻击,采取适当措施,你就能构建既安全又高效的智能合约。
关注 @TheBlockChainer,获取更多Web3安全、Solidity、智能合约审计等相关内容。