diff --git a/security/1-reentrancy/theDAO/README.md b/security/1-reentrancy/theDAO/README.md index f4885d4f4..087725ea9 100644 --- a/security/1-reentrancy/theDAO/README.md +++ b/security/1-reentrancy/theDAO/README.md @@ -1,8 +1,8 @@ # Reentrancy -Reentrancy 攻击可能导致严重的资产损失。这种攻击是如何实现的?基本上,当合约 A 调用合约 B 时,如果合约 B 再次调用合约 A 的函数,将暴露出潜在的漏洞。 +A reentrancy attack can lead to significant asset loss. How does this attack occur? Essentially, when Contract A calls Contract B, if Contract B calls back into a function in Contract A, it exposes a potential vulnerability. -以下是一个设计不当的示例代码: +Here’s an example of poorly designed code: ```solidity import "./IVault.sol"; @@ -24,7 +24,7 @@ contract BuggyVault is IVault { } ``` -如果有一个恶意合约具备恶意的 `receive()` 或 `fallback()` 函数: +If a malicious contract includes a harmful `receive()` or `fallback()` function: ```solidity pragma solidity ^0.8.7; @@ -53,28 +53,28 @@ contract Malicious { } ``` -当恶意合约调用 `BuggyVault` 的 `withdraw()` 函数时,资金传递到恶意合约的 `receive()` 函数中,导致反复调用 `withdraw()` 函数,不断地将以太坊转入恶意合约。 +When the malicious contract calls the `withdraw()` function of `BuggyVault`, funds are transferred to the malicious contract’s `receive()` function, triggering repeated `withdraw()` calls and continuously transferring Ether to the malicious contract. -虽然重入攻击可能导致严重损失,但使用 `transfer` 或 `send` 而不是 `call` 可以防止此类攻击。 +While reentrancy attacks can cause significant loss, using `transfer` or `send` instead of `call` can prevent such attacks. -- **使用 `transfer`**:`transfer` 的 gas 限制为 2300,仅足够触发事件,传输失败会触发回滚。 -- **使用 `send`**:`send` 同样有 2300 的 gas 限制,不会回滚传输失败的情况,攻击者将损失其在 Vault 中的余额而无法提取任何以太坊。 +- **Using `transfer`**: `transfer` has a gas limit of 2300, which is enough to trigger an event, and if the transfer fails, it reverts the transaction. +- **Using `send`**: `send` also has a 2300 gas limit, but it does not revert on failure, so attackers cannot withdraw any Ether if they don’t have sufficient balance in the Vault. -## 分析 +## Analysis -重入攻击的成因包括以下因素: -- **存在重入路径**:`BuggyVault` 的 `withdraw()` 函数在转账过程中调用恶意合约,激活其 `fallback()` 函数,再次调用 `withdraw()`。 -- **缺乏余额检查**:在转账前没有检查余额。 -- **缺少 gas 限制**:`call` 默认分配大量 gas,为恶意合约执行攻击提供条件。 -- **未检查传输结果**:`call` 的传输失败不会导致错误,因此应检查传输是否成功。 +The causes of a reentrancy attack include the following factors: +- **Existence of a reentrancy path**: The `withdraw()` function of `BuggyVault` calls into the malicious contract, which activates its `fallback()` function to re-enter `withdraw()`. +- **Lack of balance check**: No balance verification is done before the transfer. +- **Insufficient gas restriction**: `call` provides ample gas by default, enabling the malicious contract to execute the attack. +- **No transfer result check**: `call` doesn’t trigger an error on failed transfers, so it’s essential to verify whether the transfer succeeded. -## 最佳实践 +## Best Practices -根据以上分析,可以采用以下措施防范重入攻击: +Based on the analysis, the following measures can prevent reentrancy attacks: -### 使用 Reentrancy Guard(仅在必要时使用) +### Use a Reentrancy Guard (only when necessary) -通过状态标记防止重入调用。像 OpenZeppelin 提供的库可用于实现此功能。参考 `SafeVault1.sol`: +Prevent reentrant calls by using state flags. Libraries like OpenZeppelin provide this functionality. Refer to `SafeVault1.sol`: ```solidity pragma solidity ^0.8.7; @@ -97,15 +97,15 @@ contract SafeVault1 is IVault, ReentrancyGuard { } ``` -### 遵循“检查-影响-交互”模式(推荐) +### Follow the "Check-Effect-Interaction" Pattern (recommended) -“检查-影响-交互”模式能有效避免重入攻击: +The "Check-Effect-Interaction" pattern effectively prevents reentrancy attacks: -1. **检查 (Check)**:严格检查条件。 -2. **影响 (Effect)**:修改内部状态。 -3. **交互 (Interact)**:与外部合约进行交互。 +1. **Check**: Strictly verify conditions. +2. **Effect**: Update internal state. +3. **Interaction**: Interact with external contracts. -以下是 `SafeVault2.sol` 的示例: +Here’s an example of `SafeVault2.sol`: ```solidity pragma solidity ^0.8.7; @@ -120,12 +120,12 @@ contract SafeVault2 is IVault { } function withdraw() external override { - // 检查 + // Check require(balances[msg.sender] > 0, "Insufficient balance"); - // 影响 + // Effect uint256 balance = balances[msg.sender]; balances[msg.sender] = 0; - // 交互 + // Interaction address payable target = payable(msg.sender); (bool success,) = target.call{value: balance}(""); require(success, "Transfer failed"); @@ -133,15 +133,15 @@ contract SafeVault2 is IVault { } ``` -### 谨慎使用 `call` 进行转账(推荐) +### Carefully Use `call` for Transfers (recommended) -转账有三种方式: +There are three ways to transfer funds: -1. **`transfer`**:调用 `fallback()` 或 `receive()`,gas 限制为 2300,传输失败会回滚。 -2. **`send`**:调用 `fallback()` 或 `receive()`,gas 限制为 2300,传输失败不会回滚。 -3. **`call`**:可以指定传输 gas 并检查返回值。确保指定 gas 并检查成功状态。 +1. **`transfer`**: Calls `fallback()` or `receive()` with a 2300 gas limit and reverts on failure. +2. **`send`**: Calls `fallback()` or `receive()` with a 2300 gas limit but does not revert on failure. +3. **`call`**: Allows specifying gas and checking the return value. Be sure to specify gas and check success. -以下是 `SafeVault3.sol` 的示例: +Here’s an example of `SafeVault3.sol`: ```solidity pragma solidity ^0.8.7; @@ -161,45 +161,45 @@ contract SafeVault3 is IVault { require(success, "Transfer failed!"); balances[msg.sender] = 0; - // 或使用 transfer: + // Alternatively, use transfer: // target.transfer(balances[msg.sender]); } } ``` -## 使用说明 +## Instructions -安装依赖并运行测试: +Install dependencies and run tests: ```bash npm install npx hardhat test ``` -## 测试流程 +## Test Flow -1. **设置签名人**:在 `before` 钩子中初始化 `vaultOwner`、`maliciousUser`、`user2` 和 `user3` 作为测试参与者的地址。 +1. **Setup Signers**: Initialize `vaultOwner`, `maliciousUser`, `user2`, and `user3` as test participants in the `before` hook. -2. **第一部分 - 攻击成功测试**: - - 部署 `BuggyVault` 合约(存在重入攻击漏洞)并部署 `Malicious` 恶意合约,指向 `BuggyVault` 合约地址。 - - `maliciousUser`、`user2` 和 `user3` 分别向 `vault` 合约存款。 - - `maliciousUser` 使用恶意合约进行重入攻击调用 `withdrawFromVault` 函数。 - - 检查恶意合约的余额,确认重入攻击成功,并显示 `user2` 和 `user3` 无法再取回他们的资金。 +2. **Part 1 - Successful Attack Test**: + - Deploy the `BuggyVault` contract (with reentrancy vulnerability) and the `Malicious` contract pointing to the `BuggyVault` address. + - Have `maliciousUser`, `user2`, and `user3` deposit funds to the `vault`. + - `maliciousUser` initiates a reentrancy attack using the `withdrawFromVault` function. + - Verify that `user2` and `user3` are unable to recover their funds due to the attack. -3. **第二部分 - 因重入保护失败的攻击**: - - 部署 `SafeVault1` 合约(带重入保护机制),并将恶意合约连接到该 `vault` 合约。 - - 三个用户(`maliciousUser`、`user2` 和 `user3`)分别进行存款。 - - 尝试使用恶意合约进行重入攻击调用 `withdrawFromVault`。 - - 确认余额未被恶意用户提取,确认重入攻击失败。 +3. **Part 2 - Attack Failure due to Reentrancy Protection**: + - Deploy the `SafeVault1` contract (with reentrancy guard) and connect the malicious contract to this vault. + - Each user (`maliciousUser`, `user2`, and `user3`) makes a deposit. + - Attempt a reentrancy attack through the malicious contract’s `withdrawFromVault` function. + - Verify that the malicious user cannot extract their balance, confirming the attack failed. -4. **第三部分 - 因检查-效果-交互模式失败的攻击**: - - 部署 `SafeVault2` 合约(使用“检查-效果-交互”模式)。 - - 设置并进行存款操作。 - - 尝试使用恶意合约进行重入攻击,确认攻击失败并验证合约余额和恶意用户余额。 +4. **Part 3 - Attack Failure due to Check-Effect-Interaction Pattern**: + - Deploy the `SafeVault2` contract (using "Check-Effect-Interaction" pattern). + - Setup and make deposits. + - Attempt a reentrancy attack using the malicious contract, and verify that the attack failed, confirming contract and malicious user balances. -5. **第四部分 - 因使用 `call()` 防范失败的攻击**: - - 部署 `SafeVault3` 合约(使用限制性 `call()` 模式)。 - - 设置并进行存款操作。 - - 尝试使用恶意合约进行重入攻击,预期重入调用将会失败。 +5. **Part 4 - Attack Failure due to Restricted `call()` Use**: + - Deploy the `SafeVault3` contract (using restrictive `call()`). + - Setup and make deposits. + - Attempt a reentrancy attack, expecting the reentrancy call to fail. -这些测试通过验证不同的合约防范措施,能够有效检测 `BuggyVault` 中的重入攻击漏洞并确认防御的有效性。 \ No newline at end of file +These tests effectively detect the reentrancy vulnerability in `BuggyVault` and confirm the efficacy of the defensive measures. \ No newline at end of file