[英]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.value
是userBalances[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.