Files
nexus/wiki/concepts/Reentrancy.md

66 lines
2.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "Reentrancy"
type: concept
tags: [smart-contract, vulnerability, defi, solidity, security]
sources: [blockchain-security-auditor]
last_updated: 2026-04-25
---
## 中文定义
**重入攻击Reentrancy**:智能合约在执行外部调用后、在状态更新前,允许攻击者通过回调函数再次进入合约逻辑,从而在状态被正确更新前回滚执行、重复提取资金或操纵合约状态的漏洞类型。
## 问题描述
当合约 A 调用合约 B 的函数时,合约 B 可以在其 `receive()`/`fallback()` 函数中回调合约 A 的函数。如果合约 A 在外部调用之前读取了状态(如用户余额),但在该调用返回后才更新状态(清零余额),攻击者合约 B 可以在余额清零前回拨合约 A 的函数,再次触发提取逻辑。
## 攻击模式
### 1. 单函数重入Single-Function Reentrancy
最简单的模式同一个函数在执行中被再次调用。The DAO 和 Curve Finance 属于此类。
### 2. 跨函数重入Cross-Function Reentrancy
攻击者通过不同的函数路径重入合约,利用状态不一致进行攻击。例如:`withdraw()` 读取的余额与 `transfer()` 检查的余额不同步。
### 3. 只读重入Read-Only Reentrancy
攻击者通过 `view` 函数读取合约状态(在外部调用期间),利用该状态作为预言机输入进行攻击,无需写入合约。
### 4. ERC-777 / ERC-1155 钩子重入
即使合约没有 `receive()` 函数,使用 ERC-777 代币标准时,`transfer()` 会触发 `tokensReceived()` 钩子,攻击者可在钩子中重入。
## 防御机制
### Checks-Effects-Interactions Pattern
```solidity
// ✅ 正确顺序:先更新状态,再执行外部调用
function withdraw() external {
uint256 amount = balances[msg.sender];
require(amount > 0);
balances[msg.sender] = 0; // 先更新状态
(bool success,) = msg.sender.call{value: amount}(""); // 后外部调用
require(success);
}
```
### Reentrancy Guard
```solidity
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
contract SecureVault is ReentrancyGuard {
function withdraw() external nonReentrant {
// nonReentrant 修饰符防止任何重入
}
}
```
## 关键案例
- [[The-DAO-2016]]:历史上首个大规模重入攻击,损失 360 万 ETH直接导致 ETH/ETC 硬分叉
- [[Curve-Finance]]Vyper 编译器 bug 导致 nonreentrant 失效,损失超 7000 万美元
- [[blockchain-security-auditor]] 的 Source Page 示例代码:展示了完整的有漏洞合约和修复后合约
## 关联概念
- [[Access-Control]]:权限控制缺失会加剧重入攻击的影响
- [[Flash-Loan-Attack]]:重入攻击常与闪电贷结合使用
- Checks-Effects-Interactions Pattern标准防御模式
- [[Slither]]Slither 的 `reentrancy-eth` 检测器可发现大多数经典重入漏洞