智能合约安全专题(一):什么是重入攻击?——从 DAO 事件谈起


🛡️ 智能合约安全专题(一):什么是重入攻击?------从 DAO 事件谈起

"DAO 攻击的本质,是一个简单但致命的逻辑顺序错误。"

本文将带你看懂什么是重入攻击,它是如何发生的,又该如何避免它。


💣 一、重入攻击是什么?

重入攻击(Reentrancy Attack) 是一种利用智能合约执行过程中"外部调用未完成就重复进入当前函数"的漏洞,攻击者可以在未更新状态前多次调用目标函数,从而重复提取资金或资源

通俗理解:

本来你打算先扣钱再发货 ,结果却先发货,钱还没扣,用户多次点击"下单"就拿走了很多件货。


🧪 二、经典示例:The DAO 如何被攻击?

在 DAO 的合约中,存在如下逻辑:

复制代码
function withdraw() public {
    require(balances[msg.sender] > 0);

    // 1. 转账给用户(外部调用)
    msg.sender.call.value(balances[msg.sender])();

    // 2. 然后将余额置为0
    balances[msg.sender] = 0;
}

问题是:

  • Solidity 的 call.value() 会执行 msg.sender 的 fallback 函数(即攻击者的合约函数)

  • 攻击者的 fallback 函数中再次调用 withdraw()

  • 因为还没执行 balances[msg.sender] = 0,所以余额还在,可以再次转账

  • 如此循环,直到合约资金被耗尽

攻击者合约伪代码如下:

复制代码
function fallback() external payable {
    if (address(target).balance > 0) {
        target.withdraw();
    }
}

🧠 三、重入攻击的条件

重入攻击并不是"万能钥匙",它需要满足以下条件:

条件 描述
🔁 外部调用 目标合约必须对外部合约或地址发起调用(比如转账)
⏳ 状态延迟更新 目标合约在调用外部合约之前没有先更新状态
🔁 可重入函数 目标函数没有限制"再次调用"或"互斥锁"
💰 有利益可盗 被攻击函数能转出资金或重要资源

🛡️ 四、如何防止重入攻击?

✅ 1. 检查-效果-交互(CEI 模式

推荐做法

  1. 检查:验证参数、条件

  2. 效果:更新合约内部状态

  3. 交互:最后才调用外部合约或发送资金

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

    复制代码
     balances[msg.sender] = 0; // 状态先更新!
    
     (bool success, ) = msg.sender.call{value: amount}("");
     require(success, "Transfer failed.");

    }

✅ 2. 使用 reentrancyGuard

OpenZeppelin 提供了一个标准的 ReentrancyGuard 工具,使用 nonReentrant 修饰函数,阻止嵌套调用:

复制代码
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract Bank is ReentrancyGuard {
    function withdraw() public nonReentrant {
        // 安全的提取逻辑
    }
}

✅ 3. 使用 transfer()send() 限制 Gas

虽然不推荐(因 EIP-1884 改变 Gas 限制),但早期使用 .transfer() 的 2300 gas 限制可阻止复杂合约执行 fallback 函数。


🧯 五、重入攻击之后:Solidity 与社区的演化

DAO 攻击后,Solidity 与社区做了多项改进:

改进 描述
ReentrancyGuard 成为智能合约防御标准配置
🔧 开发者工具 各种静态分析工具支持检测重入风险(如 Slither、MythX)
🧪 安全审计 合约上线前必须通过专业审计
📝 编码规范 CEI 模式成为默认模式

🧩 六、真实案例简析

除了 DAO,还有多个知名项目因重入攻击损失惨重:

  • SpankChain(2018):因未更新状态即转账,被攻击者提走 40000 美元

  • dForce/Lendf.me(2020):DeFi 项目遭重入漏洞被盗走近 2500 万美元


🧠 七、小结

问题 回答
💥 重入攻击是如何发生的? 合约外部调用时被恶意"递归调用",因为状态尚未更新
🔐 如何防御? 按照 CEI 模式设计、使用 nonReentrant、避免复杂 fallback
🚨 教训是什么? 智能合约不可修改,必须在上线前 100% 审核与测试

📘 延伸阅读

相关推荐
用户962377954481 天前
DVWA 靶场实验报告 (High Level)
安全
数据智能老司机1 天前
用于进攻性网络安全的智能体 AI——在 n8n 中构建你的第一个 AI 工作流
人工智能·安全·agent
数据智能老司机1 天前
用于进攻性网络安全的智能体 AI——智能体 AI 入门
人工智能·安全·agent
用户962377954482 天前
DVWA 靶场实验报告 (Medium Level)
安全
red1giant_star2 天前
S2-067 漏洞复现:Struts2 S2-067 文件上传路径穿越漏洞
安全
用户962377954482 天前
DVWA Weak Session IDs High 的 Cookie dvwaSession 为什么刷新不出来?
安全
cipher3 天前
ERC-4626 通胀攻击:DeFi 金库的"捐款陷阱"
前端·后端·安全
木西3 天前
揭秘 Web3 隐私社交标杆:CocoCat 的核心架构与智能合约实现
web3·智能合约·solidity
木西5 天前
深度拆解 Grass 模式:基于 EIP-712 与 DePIN 架构的奖励分发系统实现
web3·智能合约·solidity
kida_yuan5 天前
【以太来袭】4. Geth 原理与解析
区块链