82 lines
2.6 KiB
Markdown
82 lines
2.6 KiB
Markdown
---
|
||
title: "Checks-Effects-Interactions Pattern"
|
||
type: concept
|
||
tags: [blockchain, security, smart-contract, reentrancy, best-practices]
|
||
sources: [blockchain-security-auditor]
|
||
last_updated: 2026-05-30
|
||
---
|
||
|
||
## Aliases
|
||
- Checks-Effects-Interactions
|
||
- CEI Pattern
|
||
- Checks-Effects-Interactions Pattern
|
||
|
||
## Definition
|
||
|
||
Checks-Effects-Interactions(CEI,检查-效果-交互)模式是智能合约安全编程的核心防御模式,用于防止重入攻击和其他逻辑漏洞。其核心原则是:**在执行任何外部调用之前,先完成所有的状态检查和状态更新**。
|
||
|
||
## Pattern
|
||
|
||
```
|
||
function withdraw() external {
|
||
// 1. CHECKS — 验证前置条件
|
||
require(balances[msg.sender] > 0, "No balance");
|
||
|
||
// 2. EFFECTS — 更新合约状态(在外部调用之前)
|
||
balances[msg.sender] = 0;
|
||
|
||
// 3. INTERACTIONS — 执行外部调用(最后一步)
|
||
(bool success,) = msg.sender.call{value: amount}("");
|
||
require(success, "Transfer failed");
|
||
}
|
||
```
|
||
|
||
## Why It Works
|
||
|
||
传统重入攻击利用的漏洞链:
|
||
```
|
||
外部调用(ETH转账)→ 攻击者receive()被触发
|
||
→ 攻击者 re-enter withdraw()
|
||
→ balances[msg.sender] 仍 > 0(未清零)
|
||
→ 重复提取资金
|
||
```
|
||
|
||
CEI 模式切断漏洞链:**状态在外部调用之前清零**,即使攻击者 re-enter,条件检查阶段 `require(balances[msg.sender] > 0)` 已失败。
|
||
|
||
## Common Mistakes
|
||
|
||
### Wrong Order (Vulnerable)
|
||
```solidity
|
||
// VULNERABLE: 外部调用在状态更新之前
|
||
(bool success,) = msg.sender.call{value: amount}("");
|
||
require(success);
|
||
balances[msg.sender] = 0; // 攻击者可在此之前 re-enter
|
||
```
|
||
|
||
### Missing Update (Vulnerable)
|
||
```solidity
|
||
// VULNERABLE: 状态根本没有更新
|
||
require(balances[msg.sender] > 0);
|
||
(bool success,) = msg.sender.call{value: amount}("");
|
||
require(success);
|
||
// balances[msg.sender] = 0; ← 忘记更新!
|
||
```
|
||
|
||
### ERC-20 Transfer Before Update
|
||
```solidity
|
||
// VULNERABLE: ERC-20 transfer 触发外部调用
|
||
IERC20(token).transfer(msg.sender, amount); // 外部调用
|
||
balances[msg.sender] -= amount; // 状态更新太晚
|
||
```
|
||
|
||
## Relationship to Other Defenses
|
||
|
||
- **CEI is the primary defense** — should always be applied first
|
||
- **ReentrancyGuard is additional defense** — use when CEI is difficult to apply (complex logic, callbacks)
|
||
- CEI + ReentrancyGuard together provide defense in depth
|
||
|
||
## Connections
|
||
- [[Reentrancy]] ← prevents ← [[Checks-Effects-Interactions]]
|
||
- [[Blockchain-Security-Auditor]] ← enforces ← [[Checks-Effects-Interactions]]
|
||
- [[ReentrancyGuard]] ← supplements ← [[Checks-Effects-Interactions]]
|