可重入
若一个程序或子程序可以「在任意时刻被中断然后操作系统调度执行另外一段代码,这段代码又调用了该子程序不会出错」,则称其为可重入(reentrant或re-entrancy)的。
例子如下:
function withdraw(uint_amount) public {
if(balances[msg.sender] >= _amount) {
if(!msg.sender.call.value(_amount)) { throw; }
balances[msg.sender] -= _amount;
}
}
上面的代码中,如果攻击者写一个合约来调用这个代码。那msg.sender就是攻击者的合约。msg.sender.call.value(_amount) 就是当前合约向攻击者合约发送eth,也就是当前合约调用攻击者合约的fallback函数。 如果攻击者合约的fallback函数里面,再调用当前合约的withdraw。进而重复执行msg.sender.call.value(_amount),直到gas全部消耗完毕或者合约中的以太余额全部被取完。于是就给黑客实现 reentrancy 攻击创造了条件。
解决方式:
在调用转账之前,先把余额减掉。
functionwithdraw(uint_amount) public {
if(balances[msg.sender] >= _amount) {
balances[msg.sender] -= _amount;
if(!msg.sender.call.value(_amount)) { throw; }
}
}
参考文档: http://baijiahao.baidu.com/s?id=1601249165343265192&wfr=spider&for=pc