Skip to content

Commit

Permalink
docs: ensure consistency in the README's language
Browse files Browse the repository at this point in the history
  • Loading branch information
luna2163 committed Nov 2, 2024
1 parent f328e70 commit b378793
Showing 1 changed file with 56 additions and 56 deletions.
112 changes: 56 additions & 56 deletions security/1-reentrancy/theDAO/README.md
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -120,28 +120,28 @@ 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");
}
}
```

### 谨慎使用 `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;
Expand All @@ -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` 中的重入攻击漏洞并确认防御的有效性。
These tests effectively detect the reentrancy vulnerability in `BuggyVault` and confirm the efficacy of the defensive measures.

0 comments on commit b378793

Please sign in to comment.