跨合约重入攻击
概述
跨合约重入性是指在智能合约之间发生的重入攻击,这种攻击不仅限于单一合约内部的函数调用,还可能涉及多个合约,尤其是当这些合约共享相同的状态变量时。在跨合约重入攻击中,如果状态更新不是在外部调用之前完成,那么重入可能导致严重的安全漏洞。
漏洞成因
跨合约重入通常发生在多个合约共享同一状态变量,并且其中一些合约在更新这些变量时存在安全隐患。由于涉及多个合约和共享状态,这种类型的重入问题可能更加复杂且难以发现。
漏洞示例
考虑以下简化的示例,涉及两个合约:一个银行合约和一个交易合约,它们共享一个状态变量来记录用户余额。
银行合约
contract Bank {
mapping(address => uint) public balances;
function deposit() public payable {
balances[msg.sender] += msg.value;
}
function withdraw(address to, uint amount) public {
require(balances[to] >= amount, "Insufficient funds");
(bool success, ) = to.call{value: amount}("");
require(success, "Transfer failed");
balances[to] -= amount;
}
}
交易合约
contract Trader {
Bank bank;
constructor(address _bank) {
bank = Bank(_bank);
}
function exploitWithdrawal(address to) public {
bank.withdraw(to, 100);
}
}
攻击过程
在这个场景中,如果 Trader 合约中的 exploitWithdrawal 方法能够在 Bank 合约的 withdraw方法的外部调用完成前被重入,那么可能会在Bank合约的状态更新(即balances[to] -= amount)之前多次提取资金,重入流程如下:
防范措施
防止跨合约重入的有效方法之一依旧是使用 Checks-Effects-Interactions(检查-效果-交互)模式,即首先进行所有必要的状态检查(Checks),然后更新状态(Effects),最后执行任何外部交互(Interactions)。