智能合约漏洞——Gas不足攻击(Insufficient Gas Griefing)

Gas不足攻击

  Insufficient Gas Griefing也被叫做gas不足攻击或者gas不足悲剧。主要影响执行外部调用而不检查成功的返回值的智能合约。在这种攻击中,对手可能仅提供足够的gas来确保顶层函数执行成功,同时确保外部调用由于gas耗尽而失败。这些问题在执行一般的调用的智能合约中尤其普遍,包括中继器和多签名钱包。

  下面的示例为简化的中继器合约,说明了不充分gas攻击的可能性:

/*
这是一个中继合约(Relayer contract),它允许消息从一个账户被“中继”到另一个账户,并包含一些基本的重放保护措施。
允许用户支付gas费用以外的币种或者其他方式,或者帮助用户在没有直接一台当的情况下进行交易。
*/
contract Relayer {
    //如果某个数据字节串已经被执行,则其对应的值为true。这可以防止同一个操作被多次执行,即重放攻击
    mapping (bytes => bool) executed;
    
    //中继的消息将被发送到哪个合约或账户
    address target;

    function forward(bytes memory _data) public {
        //检查提供的数据是否已经执行过。如果执行过就抛出异常
        require(!executed[_data], "Replay protection");
        
        //more code signature validation in between
        //如果数据没有被执行过,就将其标记为已执行
         executed[_data] = true;
        
        //使用低级call方法来调用目标合约的execute函数,并传入数据
        target.call(abi.encodeWithSignature("execute(bytes)", _data));
    }
}

  在forward函数内的外部调用失败时,合约可以选择恢复整个交易或继续执行。示例中的合约不检查外部调用是否成功,而是继续执行。因此,一旦完成forward函数的执行,提交的数据在已执行的映射中被标记为已执行,从而防止任何人再次提交相同的数据。

  任何第三方forwarder都可以调用forward函数来代表他们执行一个用户的交易。假设forwarder以最小的gas调用forward,仅允许Relayer合约成功但由于gas费耗尽错误导致外部调用revert(gas足够交易执行但不够调用成功)。在这种情况下,用户的交易不会被执行且用户的签名是无效的。因此,目标合约的预期状态改变将不会发生。恶意的forwarders将使用这项技术永久的地审查Replayer合约中地用户交易。即使攻击者不从悲伤攻击中获利,他们仍然可以破坏智能合约地运行,给受害者带来不便。

  有两种方式可以解决这个问题,第一种方式是只允许受信任的用户中继转发交易,另一个方案是要求forwarder提供足够的gas:

//contract called by Relayer
contract Executor {
    function execute(bytes _data, uint _gasLimit) {
        require(gasleft() >= _gasLimit);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值