Reentrancy

A reentrancy bug was the cause of the infamous attack on the DAO, where 3,600,000 of the DAO's 11,500,000 ether were drained from the DAO contract, eventually resulting in the Ethereum network forking, and the Ethereum Classic chain being created.

Here is some code that is vulnerable to this type of attack. It's a generic withdrawal function that might be seen in any type of contract that deals with ether balances:

// This code is unsafe - do not use.
mapping (address => uint) private userBalances;

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

The issue is that we are using call.value() to transfer the user's balance to their address. However, it's possible that the address belongs to a contract, and not an externally owned account (that is, a wallet address). In such a case, when we use call.value(), we are making a call into the contract's code, which could have been engineered in such a way to call withdrawBalance() again. We have therefore created a loop in which we are able to withdraw multiple times.

To mitigate this type of risk, transfer() should be used instead of call.value() (or send(), which is another option), which would prevent external code from being executed. To further protect against reentrancy, the Checks-Effects-Interactions pattern should also be used.

Let's now rewrite the vulnerable withdrawBalance() function using what we've learned:

mapping (address => uint) private userBalances;

function withdrawBalance(uint256 amount) public {
require(userBalances[msg.sender] >= amount);
userBalances[msg.sender] -= amount;
msg.sender.transfer(amount);
}

First, we conduct the necessary checks, and, in this case, the only check we need to run is that the user isn't trying to withdraw more than their balance holds. The next step is to apply the effects, which, in this case, means applying the change to the user's balance. The final step is to carry out any external calls, in this case, the transfer of the balance to the user's address.

In the vulnerable version of our function, the external interactions were carried out before the effects were applied, which led to the vulnerability and allowed a loop to exist.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset