什么是 Reentrancy Attack?
Reentrancy Attack 是指在合约调用时将控制权交给另一个合约,而该外部代码在第一个合约完成状态更新前跳回去执行。这种时机上的把戏允许攻击者重复敏感操作,比如一次又一次地提取资金。想象一下申请退款,然后在收银员锁好钱箱之前又悄悄回到柜台。
“只有老旧代码会遭受 Reentrancy Attack。”不正确。任何在锁定自身状态前进行外部调用的合约,如果逻辑不严谨,都可能存在风险。
Reentrancy Attack 的工作原理
简短示例。典型的 智能合约 有一个 withdraw 函数,会向调用者发送资金。如果合约先发送资金而后才清除余额,攻击者就可以在余额被置零之前插入回调并再次请求更多资金。
- 开始:攻击者存入一些资金以显得合法。
- 调用:攻击者触发目标合约的 withdraw 函数。
- 回调:目标合约发送资金,触发攻击者的回退函数。
- 重复:该回退再次调用 withdraw,在余额更新之前获取更多资金。
- 枯竭:循环继续,直到合约耗尽资金或 gas。是的,这就是窍门。
一个微小的顺序错误,代价巨大。
为什么 Reentrancy Attack 很重要
你需要关心,因为时序漏洞会迅速转移真实资金。此外,这是每个开发者和有兴趣的用户一眼就应能识别的经典漏洞。
- 好处:了解这种模式有助于发现有风险的代码并保护资金安全。
- 视角:它借助公开透明的特性,因为区块链上的一切可见且可被调用,因而更容易发生。 区块链
- 相关性:你会在 DeFi、跨链桥、金库,甚至面向 去中心化自治组织(DAO) 的治理支付中看到它。
遵循先检查、后生效、再交互的顺序。先更新余额,再进行外部调用。为额外安全可添加简单的重入保护。
Reentrancy Attack 的主要特征
以下是其运作要点:
- 递归:外部代码在合约完成前回调到同一合约。
- 顺序:当发送资金或外部调用发生在状态更新之前时就会出现该漏洞。
- 跨合约:它可以在多个合约之间来回触发,而不局限于单个函数。
- 资产:ETH、代币,甚至会计记账项,如果代码不当,都可能受到影响。
变体
不同形式,相同的麻烦:
- 单一:重复进入同一函数。
- 跨函数:通过合约内不同函数回入。
- 多合约:在两个或更多合约之间循环回入。
- 只读:影响视图函数或价格预言机以欺骗随后写入操作。
修复 Reentrancy Attack 不只是改一个函数。检查每次外部调用,为异常调用链添加测试,并定期安排 审计。
示例
2016 年 The DAO 被利用的事件就是利用 withdraw 在余额被清除前的重入循环,几分钟内抽干了大量金库。
趣闻
社区常说的“先检查,后生效,再交互”源自早期安全指南并流传下来,因为它简短、容易记住,而且有效。
总结
简短版便于记忆:如果外部代码能在你完成自身记账前调用你,就要假设它会这么做,否则可能白白送出资金。这就是 Reentrancy Attack。
