mirror of
https://github.com/autistic-symposium/blockchains-security-toolkit.git
synced 2025-12-12 07:06:16 -05:00
Add a simple example for reentrancy and solutions with mutex or CEI
This commit is contained in:
parent
e89d152887
commit
2bde8bfbb6
1 changed files with 72 additions and 1 deletions
|
|
@ -3,12 +3,83 @@
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
### TL; DR
|
||||||
|
|
||||||
* When a contract calls an external function, that external function may itself call the calling function.
|
* When a contract calls an external function, that external function may itself call the calling function.
|
||||||
|
* A reentrancy attack may occur when a function makes an external call to another untrusted contract. Then, the unstrusted contract makes a recursive callback to the vulnerable contract function to steal funds.
|
||||||
* To prevent this attack, a contract can implement a lock in storage that prevents re-entrant calls.
|
* To prevent this attack, a contract can implement a lock in storage that prevents re-entrant calls.
|
||||||
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
### References to learn about reentrancy
|
---
|
||||||
|
|
||||||
|
### Example of re-entrancy attack
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
For example, suppose this method:
|
||||||
|
|
||||||
|
```
|
||||||
|
function withdrawBalance() public {
|
||||||
|
uint amountToWithdraw = userBalances[msg.sender];
|
||||||
|
(bool success, ) = msg.sender.call.value(amountToWithdraw)("");
|
||||||
|
requires(success);
|
||||||
|
userBalances[msg.sender] = 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
and this exploit:
|
||||||
|
|
||||||
|
```
|
||||||
|
function() public payable {
|
||||||
|
if(msg.sender == address(vulnContract)) {
|
||||||
|
vulnContract.withdrawBalance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
How to fix?
|
||||||
|
|
||||||
|
#### Option 1: Adding a mutex locking:
|
||||||
|
|
||||||
|
```
|
||||||
|
modifier noReentrant() {
|
||||||
|
require(!locked, "nooooope");
|
||||||
|
locked = true;
|
||||||
|
_;
|
||||||
|
locked = false;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
so
|
||||||
|
|
||||||
|
```
|
||||||
|
function withdrawBalance() public noReentrant {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
#### Option 2: CEI (checks effects interaction) pattern
|
||||||
|
|
||||||
|
```
|
||||||
|
function withdrawBalance() public {
|
||||||
|
uint amountToWithdraw = userBalances[msg.sender];
|
||||||
|
userBalances[msg.sender] = 0; // update state first
|
||||||
|
(bool success, ) = msg.sender.call.value(amountToWithdraw)("");
|
||||||
|
requires(success);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
|
||||||
|
### Resources
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue