什么是重入攻击?
当合约正在执行某函数时,攻击者可以通过各种方式反复调用该函数。由于合约状态存在依赖,反复调用会破坏预期逻辑。例如合约在转账前,减少用户余额;在转账后,增加接收者余额。攻击者在余额减少时反复调用合约,就可以多次减少余额。
防止重入攻击的方法:
在函数执行前设置状态变量防重入。
避免外部合约调用。可通过接口定义安全的调用方式。
使用互斥锁 (Mutex) 防止同时调用冲突函数。
避免代币 approve 后直接调用 transferFrom, 应在两步之间检查 approve 额度。
代码示例:
// Use mutex to prevent reentrancy
Mutex mutex;
function withdraw(uint amount) external {
require(!mutex.locked());
mutex.lock();
msg.sender.call.value(amount)();
mutex.release();
}
// Use state variable to prevent reentrancy
uint256 protecting;
function withdraw() external {
require(protecting == 0);
protecting = 1;
msg.sender.transfer(balance[msg.sender]);
protecting = 0;
}