第三章:闪电贷攻击——DeFi世界的双刃剑
说实话,我第一次接触闪电贷这个概念时,第一反应是「这玩意儿也太魔幻了吧?」
零抵押、即时借款、同一笔交易内还清——听起来像天方夜谭。但以太坊的交易原子性让它变成了现实。我曾在审计一个借贷协议时,发现开发者完全没考虑闪电贷的风险,结果可想而知。
3.1 闪电贷原理:为什么能「空手套白狼」?
闪电贷的核心就一句话:在同一笔交易中借出并归还资金。
如果借款人在交易结束时没还钱,整个交易就回滚——就像什么都没发生过。这利用了以太坊的原子性特性。
关键机制:
- 借款 → 操作 → 还款 → 检查余额 → 成功/回滚
- 所有步骤在同一个区块内完成
- 无需抵押,因为「不还钱就回滚」
我习惯把闪电贷比作「图书馆借书」:你借走一本书,在图书馆关门(交易结束)前必须放回原处。放不回去?那这本书你压根没借走过。
// 闪电贷核心逻辑(简化版)
function flashLoan(uint256 amount) external {
uint256 balanceBefore = token.balanceOf(address(this));
// 1. 把币借给用户
token.transfer(msg.sender, amount);
// 2. 调用用户的回调函数
IFlashLoanReceiver(msg.sender).execute();
// 3. 检查余额是否足够(本金+手续费)
require(token.balanceOf(address(this)) >= balanceBefore + fee, "Flash loan failed");
}
3.2 典型攻击案例:那些年我见过的「骚操作」
我在2021年审计过一个项目,代码里有个明显的价格预言机漏洞。当时我就跟团队说:「这玩意儿不出一个月必被闪电贷攻击。」结果两周后就出事了。
案例一:bZx 攻击(2020年2月)
这是闪电贷攻击的「鼻祖」案例。攻击者利用闪电贷借入大量ETH,然后通过一系列操作操纵了合成资产的价格。
攻击流程:
- 从dYdX借入10,000 ETH(闪电贷)
- 用5,500 ETH在Compound做空
- 用剩下的ETH在Uniswap拉高sUSD价格
- 用拉高后的sUSD在bZx借出更多ETH
- 归还闪电贷,净赚约30万美元
说白了,攻击者就是利用不同协议之间的价格差,加上闪电贷提供的「无限弹药」。
案例二:PancakeBunny 攻击(2021年5月)
这个案例更典型。攻击者通过闪电贷操纵了BUNNY代币的价格,然后利用协议中的「铸币」功能套利。
// 攻击者核心操作(伪代码)
1. flashLoan(大量BNB)
2. swap(BNB → BUNNY) // 拉高BUNNY价格
3. deposit(BUNNY) // 存入获得高额奖励
4. withdraw() // 取出时BUNNY价格已回落
5. repay(flashLoan) // 净赚差价
嗯,这里要注意:所有依赖链上AMM价格的协议,都是闪电贷攻击的潜在目标。
3.3 价格操纵与套利:闪电贷的「正确用法」
其实闪电贷本身是中性的。它既可以被用来攻击,也可以用来做正经套利。
合法套利场景:
- DEX价差套利:在不同交易所之间搬砖
- 清算套利:帮别人还债赚清算奖励
- 抵押品替换:优化借贷仓位
我见过一个团队专门写闪电贷套利机器人,月入百万美元。他们用的就是同一套技术——只是没去碰那些有漏洞的协议。
为什么会有人用闪电贷做套利?因为资金效率高啊。你想想看,传统套利需要准备大量本金,闪电贷让你零成本起步。
3.4 防御策略:如何让你的协议「百毒不侵」
我曾经审计过一个项目,代码写得挺漂亮,但就是没防闪电贷。我跟他们说:「你们这个价格预言机,随便一个闪电贷就能打穿。」
下面是我总结的防御策略,每一条都是血泪教训:
| 策略 | 说明 | 我踩过的坑 |
|---|---|---|
| 使用TWAP预言机 | 用时间加权平均价格,而非瞬时价格 | 有个项目用Uniswap即时价格,被闪电贷打爆 |
| 引入价格延迟 | 价格更新后延迟一段时间才生效 | 延迟太短等于没延迟 |
| 限制单笔交易规模 | 设置最大可操作金额 | 但太保守会影响用户体验 |
| 检查交易来源 | 禁止合约调用(仅限EOA) | 但会误伤闪电贷套利机器人 |
| 使用Chainlink等去中心化预言机 | 聚合多个数据源,抗操纵 | 成本较高,但值得 |
我的核心建议:
- 永远不要信任单笔交易内的价格数据
- 所有关键价格必须使用外部预言机或TWAP
- 对闪电贷攻击做专门的单元测试
- 设置合理的滑点保护
我曾经在一个项目中看到这样的代码:
// ❌ 危险写法:直接使用池子即时价格
uint256 price = uniswap.getReserves() / totalSupply;
// ✅ 安全写法:使用TWAP
uint256 price = uniswap.consult(tokenIn, amountIn, 30 minutes);
就这一行代码的区别,决定了协议是安全还是等着被薅羊毛。
3.5 知识体系总览
下面这张图是我自己画的,把闪电贷攻击的整个知识体系串起来了:
这张图把闪电贷攻击的三大块串起来了:攻击案例、价格操纵、防御策略。核心就一句话——别信瞬时价格。
避坑指南:
我曾经审计过一个项目,他们用了Uniswap V3的TWAP预言机,但时间窗口设成了1分钟。我告诉他们:「1分钟太短了,闪电贷可以在一个区块内完成攻击。」最后改成了30分钟,安全多了。
好了,闪电贷这块就聊到这儿。记住:闪电贷本身不是问题,问题在于你的协议有没有为它做好准备。