首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在锁之间进行多次支付安全吗(重入守卫)?

在锁之间进行多次支付安全吗(重入守卫)?
EN

Ethereum用户
提问于 2020-01-02 21:45:16
回答 1查看 374关注 0票数 1

https://diligence.consensys.net/blog/2019/09/stop-using-soliditys-transfer-now/提供了一个与使用Reentrancy Guard相关的简单示例。

另一种防止重入的方法是显式检查和拒绝此类调用。下面是可重入守卫的一个简单版本,您可以看到这个想法:

代码语言:javascript
复制
contract Guarded {
     ...

     bool locked = false;

     function withdraw() external {
         require(!locked, "Reentrant call detected!");
         locked = true;
         ... // Multiple Payments
         locked = false;
    }
}

但是在这里,我认为还有另一个问题,如果检测到重入调用,withdraw()函数将被返回,而locked仍然是true。因此,我们将无法在进一步的调用中重新输入withdraw()函数,因为locked仍然是true

问:在锁之间多付不同的费用安全吗?一个例子如下:

代码语言:javascript
复制
contract Guarded {
     ...
     bool locked = false; 

     function withdraw() external {             
         require(!locked, "Reentrant call detected!");
         locked = true;

         // Payment-1         
         (bool success, ) = msg.sender.call.value(balanceOfPayment1[msg.sender])("");
         require(success, "Transfer failed.");
         balanceOfPayment1[msg.sender] = 0;

         // Payment-2         
         (bool success, ) = msg.sender.call.value(balanceOfPayment2[msg.sender])("");
         require(success, "Transfer failed.");
         balanceOfPayment2[msg.sender] = 0;

         locked = false;
    }
}
EN

回答 1

Ethereum用户

回答已采纳

发布于 2020-01-03 01:13:19

不是的。

您的互斥锁(locked)将阻止重新进入,但重入并不是唯一的漏洞。

DoS是可能的,它可能不是故意的。

这一行,付款后2:

require(success, "Transfer failed.");

您是否考虑过,如果交易在此阶段中止,付款1将不会发生?这意味着,除非player1合作,否则player2是不会得到报酬的。

许多开发人员认为不能拒绝付款,这样做是不可取的,因此很可能不会发生这种情况,但这些假设会给您带来麻烦。

  1. 合同的默认行为是拒绝获得备用函数的资金,因为合同通常有会计要求,并且可能需要额外的数据--这些数据不包括在这样的transfer.中,即.call。在没有解释的情况下,合同要做的最安全的事情就是还原,这样做可能会使整个事务恢复正常。如果任何一个transfers失败,您的函数将完全恢复整个事务(都是transfer )。
  2. 可能会有经济上的诱因让你的合同失效。例如,它可能会锁定资金,给竞争对手带来尴尬或灾难,或者仅仅是为了娱乐。
  3. 如果这类事情在贡献者(或未展开的)列表的循环中,攻击者只需安排一些事情,因此其中的一个接收者就是一个契约,例如注册契约并做出一个可退还的小贡献。
  4. 我知道您会在其他地方读到关于检测和避免合同的技术,但是这种方法不会抵抗攻击,并且可能会降低项目的有用性,因此避免在此基础上进行区分。

建议采用退出模式。也就是说,进行会计核算,让用户通过为此目的建立的函数来申请他们的资金。这样,每个交互中只有一个“不受信任”的参与者,即msg.sender。这样做可以将关注点分开,这样他们就更不可能互相干涉。

为了清晰。锁应该完成它的工作,即防止重新进入,但是单个事务中的多个传输是一个错误的方向,因为它会带来相当大的风险。

希望能帮上忙。

票数 2
EN
页面原文内容由Ethereum提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://ethereum.stackexchange.com/questions/78675

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档