Use the checks-effects-interactions pattern

Be very careful when interacting with other external contracts, it should be the last step in your function. It can introduce several unexpected risks or errors. External calls may execute malicious code. These kinds of calls should be considered as potential security risks and avoided if possible.

pragma solidity ^0.4.24;
// THIS CONTRACT is INSECURE - DO NOT USE
contract Fund {
mapping(address => uint) userBalances;
function withdrawBalance() public {
//external call
if (msg.sender.call.value(userBalances[msg.sender])())
userBalances[msg.sender] = 0;
}
}
contract Hacker {
Fund f;
uint public count;

event LogWithdrawFallback(uint c, uint balance);

function Attacker(address vulnerable) public {
f = Fund(vulnerable);
}
function attack() public {
f.withdrawBalance();
}


function () public payable {
count++;
emit LogWithdrawFallback(count, address(f).balance);
if (count < 10) {
f.withdrawBalance();
}
}
}
}

The line msg.sender.call.value(userBalances[msg.sender]) is an external call, when withdrawBalance is called, it will send ether with the address.call.value(). The hacker can attack fund contracts by triggering the hack fallback function, which can call the withdrawBalance method again. This will allow the attacker to refund multiple times, draining all ether in accounts.

The preceding contract vulnerabilities is called reentrancy. To avoid this, you can use the checks-effects-interactions pattern, shown in the following example:

pragma solidity ^0.4.24;
contract Fund {
mapping(address => uint) userBalances;
funct
ion withdrawBalance() public {
uint amt = userBalances[msg.sender];
userBalances[msg.sender] =0;
msg.sender.transfer(amt);
}
}

We first need to identify which part of the function involves external calls, uint amt = userBalances[msg.sender]; userBalances[msg.sender] =0;.

The function reads userBalances value, and assigns it to a local variable, then it resets  userBalances. These steps are to make sure message sender can only transfer to their own account, but can't make any changes to state variables. The balance of a user will be reduced before the ether is actually transferred to user. If any error occurs during the transfer, the whole transaction will be reverted, including the reduction transfer amount of balance in the state variable. This approach can be described as optimistic accounting, because effects are written down as completed, before they actually take place.

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

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