問題一覧に戻る
上級セキュリティパターン
問題75: 再入攻撃対策
Solidityの再入攻撃防止を学習します - 最も重要なセキュリティパターンです。再入攻撃は、外部呼び出しが状態更新完了前に関数への再入を許可することで発生します。Checks-Effects-Interactions(CEI)パターンがこれを防ぎます:最初に条件を検証、次に状態を更新、最後に外部コントラクトと相互作用。ReentrancyGuard修飾子が追加の保護を提供します。The DAOなどの大規模ハックの原因となったため、再入攻撃の理解は不可欠です。
pragma solidity ^0.8.0;
contract ReentrancyGuard {
mapping(address => uint256) public balances;
bool private locked;
modifier nonReentrant() {
require(!locked, "No reentrancy");
locked = true;
_;
locked = false;
}
// 脆弱:状態更新前の外部呼び出し
function withdrawBad() public {
uint256 balance = balances[msg.sender];
// 間違った順序:状態変更前の呼び出し
(bool success, ) = msg.sender.call{value: balance}("");
require(success, "Transfer failed");
balances[msg.sender] = ;
}
// 安全:CEIパターンに従う
function withdrawGood() public {
uint256 balance = balances[msg.sender];
require(balance > 0, "No balance");
// CEI:最初に状態を更新
balances[msg.sender] = ;
// その後外部呼び出し
(bool success, ) = msg.sender.call{value: balance}("");
require(success, "Transfer failed");
}
}