我们的BNB3项目目前处于推广阶段了!希望尊敬的各位程序员来加入!
最近DEXX被盗了😂,我又双叒开始入门合约安全!确实,在web2似乎很少遇见hacker,但是在新的领域,真的需要各位优秀的程序员加入!!
什么是智能合约中的重入攻击?如何防范这种攻击?
防范措施:
- 使用 Checks-Effects-Interactions 模式:先进行检查,修改合约状态,再与外部合约交互。
- 使用 Reentrancy Guard:通过在合约中引入状态标志,防止重入调用。
攻击原理
- 合约 A 调用合约 B 的一个函数,转账或执行其他逻辑。
- 合约 B 在逻辑中调用外部合约 C(通常是攻击者的合约)。
- 合约 C 的回调函数再次调用合约 A 的函数,而此时合约 A 尚未完成状态更新,可能导致重复执行敏感逻辑(例如转账资金),从而被攻击者多次利用。
Vulnerable 合约
这是一个简单的提款合约,用户可以存款并提取他们的余额,但存在重入漏洞。
Attacker 合约 攻击者合约通过构造恶意逻辑,在回调函数中反复调用
withdraw
函数,窃取 Vulnerable 合约的资金。
解决办法
-
将状态更新放在外部调用之前(采用检查-效应-交互模式)。
solidityfunction withdraw(uint256 amount) public nonReentrant { require(balances[msg.sender] >= amount, "Insufficient balance"); // 更新余额 balances[msg.sender] -= amount; // 转账操作 (bool success, ) = msg.sender.call{value: amount}(""); require(success, "Transfer failed"); }
-
使用 OpenZeppelin 的
ReentrancyGuard
防止重入攻击。
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract SecureContract is ReentrancyGuard {
mapping(address => uint256) public balances;
// 用户存款
function deposit() public payable {
balances[msg.sender] += msg.value;
}
// 防止重入的提款函数
function withdraw(uint256 amount) public nonReentrant {
require(balances[msg.sender] >= amount, "Insufficient balance");
// 更新余额
balances[msg.sender] -= amount;
// 执行外部调用
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
}
// 获取合约余额
function getContractBalance() public view returns (uint256) {
return address(this).balance;
}
}
ps: BNB3平台在测试上线了,欢迎各位来玩😊