Reentrancy attacks happen when a program lets another program call back into it before finishing its work. This can cause unexpected problems like losing money or data.
0
0
Reentrancy attacks in Blockchain / Solidity
Introduction
When writing smart contracts that handle money transfers.
When you want to protect your contract from being tricked by repeated calls.
When you need to make sure your contract finishes one task before starting another.
When you want to understand how hackers might try to steal funds from your contract.
When testing your contract for security before deploying it.
Syntax
Blockchain / Solidity
function withdraw(uint amount) public {
require(balances[msg.sender] >= amount);
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
balances[msg.sender] -= amount;
}This example shows a vulnerable withdraw function in Solidity.
The call to send money happens before updating the balance, which can be exploited.
Examples
This fixes the problem by updating the balance before sending money.
Blockchain / Solidity
function withdraw(uint amount) public {
require(balances[msg.sender] >= amount);
balances[msg.sender] -= amount;
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
}This uses a lock to prevent the function from being called again before it finishes.
Blockchain / Solidity
bool locked; modifier noReentrancy() { require(!locked, "No reentrancy"); locked = true; _; locked = false; } function withdraw(uint amount) public noReentrancy { require(balances[msg.sender] >= amount); balances[msg.sender] -= amount; (bool success, ) = msg.sender.call{value: amount}(""); require(success); }
Sample Program
This contract lets users deposit and withdraw money. The withdraw function is vulnerable because it sends money before updating the balance.
Blockchain / Solidity
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Vulnerable { mapping(address => uint) public balances; function deposit() public payable { balances[msg.sender] += msg.value; } function withdraw(uint amount) public { require(balances[msg.sender] >= amount, "Insufficient balance"); (bool success, ) = msg.sender.call{value: amount}(""); require(success, "Transfer failed"); balances[msg.sender] -= amount; } }
OutputSuccess
Important Notes
Always update balances before sending money to prevent reentrancy.
Use a reentrancy guard (lock) to block repeated calls during execution.
Test your contracts with attack simulations to find vulnerabilities.
Summary
Reentrancy attacks happen when a contract calls back into itself before finishing.
Update state before sending money to avoid this attack.
Use locks or modifiers to protect your functions.