我想分享一件相当重要但你可能还不太清楚的事情——那就是智能合约中的重入漏洞。如果你正在开发去中心化应用(dapp)或与区块链打交道,这个知识点是必须掌握的。



重入漏洞的基本问题是什么?它发生在一个智能合约调用另一个合约时,而被调用的合约可能在执行过程中再次调用原始合约。攻击者可以利用这个时间差来窃取资金。

想象一下,ContractA 持有 10 Ether,而 ContractB 已经向它发送了 1 Ether。当 ContractB调用提款函数时,ContractA会检查余额是否大于0,如果是,就会向它返回 Ether。但这里的问题是——ContractA只在发钱后才更新余额。因此,在发钱的过程中,如果ContractB有一个fallback函数,它可以再次调用ContractA的提款函数。由于余额还没有被更新,检查依然通过,它又会多获得1 Ether。这个循环会持续,直到ContractA的余额耗尽。

我将告诉你三种保护合约免受重入攻击的方法。

第一种是使用nonReentrant修饰符。这个思路非常简单——在函数执行时锁住合约。如果有人试图再次调用这个函数,它会被拒绝,因为合约处于锁定状态。你必须等函数执行完毕后才解锁,此时再次调用会失败。

第二种是采用“检查-效果-交互”模式。不是在发钱后再更新余额,而是在检查余额后立即更新,但在发钱之前。这样,即使其他合约再次调用,余额也已经变成0了,检查就会失败。这也是为什么顺序非常重要——先检查,再更新状态,最后与其他合约交互。

第三种是创建一个单独的GlobalReentrancyGuard合约,特别适合多个合约相互调用的场景。不是为每个函数单独保护,而是建立一个共享的守卫合约,用来存储锁定状态。当任何合约试图调用受保护的函数时,它会先检查这个守卫合约。如果守卫显示合约已被锁定,交易就会被拒绝。这种方式非常强大,因为它可以防止多个合约之间的重入攻击。

我建议你根据具体情况采用这三种技术中的一种或多种。对于提款或转账操作,始终使用nonReentrant或“检查-效果-交互”模式。如果你的项目涉及复杂的合约系统,也可以考虑引入GlobalReentrancyGuard作为额外的保护层。

这是最常见的导致重大资金损失的漏洞之一,理解重入漏洞非常重要,只有这样你才能写出安全的智能合约。
XCH0.13%
TRA0.68%
XEM-1.30%
查看原文
此页面可能包含第三方内容,仅供参考(非陈述/保证),不应被视为 Gate 认可其观点表述,也不得被视为财务或专业建议。详见声明
  • 赞赏
  • 评论
  • 转发
  • 分享
评论
请输入评论内容
请输入评论内容
暂无评论