《我学区块链》—— 三十一、以太坊安全之 可重入漏洞

三十一、以太坊安全之 可重入漏洞

如果一个函数在执行完成前被调用了数次,发生意料不到的行为时,可重入漏洞就可能出现。

我们看看下面这个函数,它可以用于从合约中提取调用者的总余额:

mapping (address => uint) private balances;
function payOut () {
    require(msg.sender.call.value(balances[msg.sender])()); 
    balances[msg.sender] = 0;
}

调用 call.value() 会导致合约外部代码的执行。即,若调用者是另一份合约,这就意味着合约回退措施的执行。这可能会在余额调整为 0 之前再次调用 payOut(),从而获得比可用资金更多的资金。

这种情况下的解决方法就是使用替代函数 send() 或 transfer(),后两者函数能为基础运作提供足够的 Gas,而想要再次调用 payOut() 时 Gas 就不足了。

注意,下面这句话也十分重要:

“若合约含有两个共享状态的函数,那么不需要重复调用函数也可能会发生相似的竞态条件(Race Conditions)。”

因此,最好的做法是在转账前更改状态,即转移资金前,在上述代码中把余额设为 0。

The DAO 攻击利用了该漏洞的一种变体。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值