Solidity

在鎖之間進行多次支付是否安全(Reentrancy Guard)?

  • January 3, 2020

https://diligence.consensys.net/blog/2019/09/stop-using-soliditys-transfer-now/提供了一個與使用Reentrancy Guard.

另一種防止重入的方法是明確檢查並拒絕此類呼叫。這是可重入保護的簡單版本,因此您可以看到這個想法:

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.


**$$ Q $$**在鎖之間進行多次不同的付款是否安全?一個例子如下:

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;
   }
}

不。

您的 Mutex ( locked) 將阻止重入,但重入並不是唯一的漏洞。

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

此行,付款後 2:

require(success, "Transfer failed.");

您是否考慮過如果在此階段交易中止,付款 1 將不會發生?這意味著除非 player2 合作,否則 player1 不會獲得報酬。

許多開發人員假設付款不能被拒絕,並且這樣做是不可取的,因此它可能不會發生,但這些假設會給你帶來麻煩。

  1. 合約的預設行為是拒絕到達備份函式的資金,因為合約通常有會計要求並且可能需要額外的數據——這些東西不包含在這樣的transfer.a 中.call。當意外資金到達而沒有解釋時,合約最安全的做法是還原,這樣做可能會使整個交易還原。如果其中一個失敗 ,您的函式將完全恢復整個事務(兩者)。transfers transfer
  2. 可能有經濟誘因使您的契約失敗。例如,它可能會鎖定資金並給競爭對手造成尷尬或災難,或者只是為了娛樂。
  3. 如果這類事情在貢獻者列表中循環(或展開),則攻擊者只需安排事情,以便其中一個接收者是契約,例如註冊契約並進行少量可退還的貢獻。
  4. 我知道您會在其他地方閱讀有關檢測和避免契約的技術,但該方法無法抵禦攻擊,並且可能會降低您項目的實用性,因此請避免在此基礎上進行歧視。

推薦使用撤回模式。也就是說,進行會計並讓使用者使用為此目的建構的功能來索取他們的資金。這樣,每次互動中只有一個“不受信任”的參與者,即msg.sender. 這樣做可以將關注點分開,這樣它們就不太可能相互干擾。

為了清楚起見。鎖應該做它的工作,即防止重入,但是在單個事務中進行多次傳輸是一個不好的方向,因為它帶來了相當大的危害。

希望能幫助到你。

引用自:https://ethereum.stackexchange.com/questions/78675