可怕的外部调用?
往往对于一个功能成熟的DAPP
,如uniswapV2,多签钱包等,都是通过多个智能合约实现的,那么就多多少少都会涉及到外部的调用,然而这就带来的很大的风险。如果不能确保外部调用的合约是正常且不带恶意逻辑代码,那么对自身合约就是个定时炸弹,不知道哪天就调用了一个不正常的恶意合约,引爆炸弹。
外部调用会引发的一些常见漏洞:重入攻击,外部合约的安全性问题,重放攻击等
具体来看一下代码:
function deposit( |
这是一个质押合约 RewardsAdvisor中的部分代码,它接受 FARM 代币并铸造等量的 xFARM。xFARM 用于治理defi 生态系统。
通过以上代码。我们发现当质押合约接受xFARM时,如果对面是合约A,不是外部账户,那么质押合约就会调用这个合约A的delegatedTransferERC20,来进行代币的转移,可是,质押合约并没有对转移后代币数量的检查等,所以,合约A中delegatedTransferERC20函数如果什么也没有实现,质押合约也会认为代币接受成功了,这将会引起一个可怕的后果。
同样。也有以下代码:
function stakeFor(address _for, uint256 _amount) public { |
也是一个质押合约中的部分代码,进行外部调用 stakingToken.safeTransferFrom(msg.sender, address(this))
,都是没有对调用后进行一个检查,攻击者就可以乘虚而入,如:TempleDAO 的 STAX 在2022年就因为同样的原因被黑客入侵,损失了价值约 $2.3M 的 LP 代币。再者就是Visor合约(实现铸造无限奖励),黑客通过利用同样的原理实现了经济套利,铸造了 195k 个 vVISR 代币。然后,这些被burn
为 8.8M VISR,通过 Uniswap v2 交换为 ETH,获得了113 ETH(450 美元)。案例1参考 案例2参考
但是,外部调用并不可怕,您可以通过以下措施来防范:
1,使用状态变量控制,在执行外部调用之前先更新合约状态,防止重入攻击。
2,采用检查-效果-交互模式,将合约操作分为三个阶段,确保在外部调用前完成所有状态更新。
3,实现重入保护,使用互斥锁(例如 nonReentrant 修饰符)来防止重入攻击。
4,通过权限控制,确保只有经过授权的用户可以执行特定操作,使用 Ownable 或类似的库来管理权限。
5,使用受信任的外部合约,在与其他合约交互时,确保只与信誉良好的合约交互,避免不必要的风险。