簡體   English   中英

關於再入攻擊的智能合約良好做法

[英]Smart contract good practice for reentrancy attacks

我是一個使用固態和區塊鏈技術的新手,我正在閱讀一些改進代碼的良好實踐。

我有一個關於我不太了解的代碼的問題:

來源https : //github.com/ConsenSys/smart-contract-best-practices/blob/master/docs/known_attacks.md

// INSECURE
mapping (address => uint) private userBalances;

function withdrawBalance() public {
    uint amountToWithdraw = userBalances[msg.sender];
    require(msg.sender.call.value(amountToWithdraw)()); // At this point, the caller's code is executed, and can call withdrawBalance again
    userBalances[msg.sender] = 0;
}

上面的代碼被稱為不安全的,因為惡意代理可以調用​​步驟2所需的次數。 關於這個問題,我的問題是,惡意代理如何調用該濫用代碼並多次調用該代碼行。 我顯然在這里錯過了一些東西。

這稱為再入攻擊。

這是不安全的,因為僅在處理提款后,用戶的余額才設置為0。 而且,提款是使用evm的CALL操作碼處理的,它將控制權傳遞給接收地址。

如果接收地址是合同,則可以使用后備功能劫持此轉移。 在此后備功能內,它可以檢查發送合同的余額是否超過已轉移的金額。 如果是這樣,它將再次調用withdrawBalance ,直到提款合約的余額用完為止。

一個簡單的攻擊者合同可能看起來像:

contract Attacker {

    function startattack() {
        victim.withdrawBalance();
    }

    function() payable {
        if (victim.balance > msg.value) {
            victim.withdrawBalance();
        }
    }
}

通過調用startattack ,您可以開始取款。 require(msg.sender.call.value(amountToWithdraw)()); 行執行后,它將運行后備功能中的代碼。 此時, msg.valueuserBalances[msg.sender] 攻擊者可以檢查受害人的合同是否還有比userBalances[msg.sender]可用的userBalances[msg.sender] ,然后再次運行提款(這將導致該過程循環進行,直到余額下降到userBalances[msg.sender] )。

可以通過將行的順序切換為以下方式來避免這種情況:

function withdrawBalance() public {
    uint amountToWithdraw = userBalances[msg.sender];
    userBalances[msg.sender] = 0;
    require(msg.sender.call.value(amountToWithdraw)());
}

現在,即使攻擊者再次調用withdrawBalance ,用戶的余額已被設置為0,並且將無法進一步取款。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM