智能合约安全——重入漏洞

  • 重入漏洞概述:以太坊智能合约在转账时会触发fallback函数,攻击者可利用此机制在fallback中植入恶意代码,通过循环调用合约的提现函数窃取资金。

  • 漏洞示例:展示了一个典型存在重入漏洞的充提合约代码,关键问题在于withdraw函数先转账后清零余额,导致攻击者可重复提款。

  • 攻击手法

    • 攻击合约通过fallback函数在收到转账时递归调用目标合约的withdraw函数。
    • 利用流程图说明攻击循环:充值→提现→触发fallback→再次提现→直至合约资金耗尽。
  • 修复方案

    • 遵循"检查-生效-交互"(Checks-Effects-Interactions)编码规范。
    • 使用防重入锁(如nonReentrant修饰符)阻止递归调用。
    • 警惕所有外部合约调用,默认视其为潜在风险点。
  • 防御代码示例:展示了通过状态锁变量实现的重入保护机制,确保函数执行期间不会被重复进入。

总结

重入漏洞相信大家都有所耳闻,那么什么是重入漏洞呢?

众所周知,以太坊的转账不仅可以在钱包地址之间进行,合约与钱包地址之间、合约与合约之间也可以,而合约在接收到转账的时候会触发 fallback 函数执行相应的逻辑,这是一种隐藏的外部调用。攻击者就会利用这一点,在合约的fallback 函数中写入恶意逻辑重新进入到被攻击的合约内部,让被攻击的合约执行非预期的外部调用,从而到达获取不正当利益的目的。

漏洞示例

下面我们来看一个比较典型的有重入漏洞的代码:

智能合约安全——重入漏洞

漏洞分析

上面的代码就是个普通的充提币的合约,那么怎么对其发起重入攻击呢?我们来看这个合约的 withdraw 函数,这个函数中的转账操作有一个外部调用“msg.sender.call{value: bal}”,所以我们就可以认为这个合约是可能有重入漏洞的,让我们来进一步分析看看:

在 withdraw 函数中是先执行外部调用进行转账后才将账户余额清零的,那么就可以在转账外部调用的时候构造一个恶意的逻辑合约在合约执行 balance[msg.sender]=0之前一直循环调用 withdraw 函数一直提币从而将合约账户清空。

攻击合约

下面我们看看攻击者编写的攻击合约中的攻击手法是否与我们的漏洞分析相同:

智能合约安全——重入漏洞

我们看到 EtherStore 合约是一个充提合约,我们可以在其中充值和提现。

攻击者先调用合约中的攻击函数先向EtherStore中充值1ether,在EtherStore中他的账户余额就为1ether,那么他就可以提现这些余额。紧接着,withdraw 函数发起提现,当EtherStore向攻击合约转账完成时,攻击合约就会调用fallback函数,再次请求提现余额,如此循环就能将EtherStore中的余额提现到不足1ether,才结束这个循环。

攻击函数调用流程图:

智能合约安全——重入漏洞

修复建议

看了上面的攻击手法相信大家对重入漏洞都会有一个自己的认知了,但是我们的应该怎么避免重入漏洞防御重入攻击呢?以下是我给大家的建议:

1. 写代码时需要遵循先判断,后写入变量在进行外部调用的编码规范(Checks-Effects-Interactions)。

2. 加入防重入锁。

下面是一个防重入锁的代码示例:

智能合约安全——重入漏洞

3. 记住所有涉及到外部合约调用的代码位置都是不安全的。

那么智能合约中的重入攻击就讲解完了,如果想了解更多的区块链知识,或是有什么疑问,可以到区块链交流社区CHAINPIP来,一起学习和交流。

社区地址:https://www.chainpip.com/

分享至:

作者:fingernft

本文为PANews入驻专栏作者的观点,不代表PANews立场,不承担法律责任。

文章及观点也不构成投资意见

图片来源:fingernft如有侵权,请联系作者删除。

关注PANews官方账号,一起穿越牛熊
推荐阅读
2022-07-29 07:21
2022-07-29 07:00
2022-07-29 06:57
2022-07-29 06:56
2022-07-29 06:26
2022-07-29 05:49

热门文章

行业要闻
市场热点
精选读物

精选专题

App内阅读