2.6 KiB
2.6 KiB
title, type, tags, sources, last_updated
| title | type | tags | sources | last_updated | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Checks-Effects-Interactions Pattern | concept |
|
|
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)
// VULNERABLE: 外部调用在状态更新之前
(bool success,) = msg.sender.call{value: amount}("");
require(success);
balances[msg.sender] = 0; // 攻击者可在此之前 re-enter
Missing Update (Vulnerable)
// VULNERABLE: 状态根本没有更新
require(balances[msg.sender] > 0);
(bool success,) = msg.sender.call{value: amount}("");
require(success);
// balances[msg.sender] = 0; ← 忘记更新!
ERC-20 Transfer Before Update
// 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