重入攻击(Reentrancy Attack)是区块链历史上最著名、也最具教育意义的智能合约漏洞之一。2016 年震动整个行业的 The DAO 事件,正是由重入漏洞引发,直接导致以太坊硬分叉。本文做一次系统的科普,帮助初学者理解它为什么危险、如何发生、又该如何防范。如果你正在学习 科普智能合约审计 相关知识,重入攻击几乎是绕不开的第一课。
重入攻击是什么
重入,顾名思义就是"重复进入"。在以太坊这类支持智能合约的平台上,一个合约在执行过程中可以调用另一个合约。当合约 A 向合约 B(或某个外部地址)转账时,会触发对方的接收函数,而这个接收函数可以在 A 尚未完成自身状态更新之前,反过来再次调用 A 的某个函数——这就是"重入"。
问题在于:如果 A 把"转账"放在"扣减余额"之前,攻击者就能在余额还没被减少时,反复触发提款逻辑,像循环抽水一样把合约里的资金掏空。理解这一点,对学习 科普DeFi 和 科普DEX 中的资金安全机制非常关键。
攻击机制原理
经典的可被攻击的提款函数大致是这样的执行顺序:
- 检查调用者的余额是否充足;
- 通过
call向调用者地址转账(外部调用); - 把调用者的余额清零或扣减。
漏洞就藏在第 2 步和第 3 步的顺序里。第 2 步的外部调用会把控制权交给攻击合约,而此时第 3 步还没执行,调用者在合约账本里的余额仍是满的。攻击合约在收款回调里再次调用提款函数,检查依然通过,于是又转账一次……如此递归,直到合约余额耗尽或 Gas 用尽。
这也是为什么很多 科普智能合约审计 报告会把"外部调用先于状态更新"列为高危项。涉及资金流动的合约,无论是借贷、科普永续合约,还是普通的 科普LP代币 提取,都可能踩到同一个坑。
典型受害场景
重入并不只出现在简单的提款函数中。常见的高危场景包括:
- 跨合约组合调用:DeFi 乐高式拼装让一次交易跨越多个协议,调用链变长,重入面也变大。
- 闪电贷放大:攻击者用极低成本借入大额资金,配合重入把损失放大到惊人规模,想深入了解可参考 闪电贷视频教程。
- ERC-777 等带回调的代币标准:转账自带钩子函数,比普通 ERC-20 更容易触发重入。
历史上多起 DeFi 被盗事件都与重入或其变种(如只读重入、跨函数重入)有关。
防御方法与最佳实践
防御重入并不复杂,核心是遵循几条久经考验的原则:
检查-生效-交互模式(Checks-Effects-Interactions)
把代码顺序调整为:先检查条件,再更新本合约状态(如扣减余额),最后才做外部调用。这样即便攻击者重入,余额早已被清零,再次检查就无法通过。这是最根本、成本最低的防线。
重入锁(Mutex)
使用一个状态变量作为"门闩",函数进入时上锁、退出时解锁,重入调用会因为锁已占用而直接回退。OpenZeppelin 的 ReentrancyGuard 就是这种思路的标准实现。
限制外部调用与 Gas
谨慎使用低级 call,对不可信外部地址保持警惕。良好的工程习惯还包括做好 Gas优化进阶教程 中提到的边界控制,避免逻辑在复杂调用链中失控。
充分审计与测试
上线前做完整的 科普智能合约审计,结合静态分析工具与人工复审,覆盖只读重入、跨合约重入等边角情形。学习 DApp前端代码示例 的同时,也要建立"链上一切外部调用都不可信"的安全心态。
常见问题与风险提示
问:把资产放进硬件钱包就能避免重入攻击吗? 不能。重入是合约层漏洞,详解冷钱包 保护的是你的私钥安全,无法修复你交互的协议本身的缺陷。两者解决的是不同层面的风险。
问:审计通过的合约就绝对安全吗? 不是。审计能显著降低风险,但无法保证零漏洞。历史上不乏审计后仍被攻破的案例,使用任何 DeFi 协议都应自行评估,了解 有什么风险DEX 这类问题的答案。
问:普通用户能做什么? 优先选择经过多轮审计、运行时间长、TVL 稳定的成熟协议;对新上线、匿名团队、收益异常高的项目保持警惕,谨防 科普跑路盘。
需要提醒的是,本文仅作技术科普,不构成任何投资建议。智能合约安全是一个持续演进的领域,攻击手法不断翻新,参与链上活动前请务必做好功课、控制仓位、量力而行。理解重入攻击,是建立链上安全意识的第一步,但远不是终点。