@@ -15,6 +15,85 @@ timezone: UTC+8
1515## Notes
1616
1717<!-- Content_START -->
18+ # 2025-08-15
19+
20+ ## 安全實踐 -- 常見攻擊手段
21+
22+ ### 重入攻擊(Reentrancy Attack)
23+ 合約呼叫外部合約或地址(例如 call 發送 ETH)時,對方在交易完成前又回頭呼叫原本合約的同一個函數,導致邏輯重複執行,造成意料外的狀況(通常是多次提款)。
24+
25+
26+ 典型範例(易受攻擊)
27+ ``` solidity=
28+ function withdraw(uint amount) public {
29+ require(balances[msg.sender] >= amount, "Not enough balance");
30+
31+ // 1. 轉錢給使用者
32+ (bool success, ) = msg.sender.call{value: amount}("");
33+ require(success, "Transfer failed");
34+
35+ // 2. 更新餘額
36+ balances[msg.sender] -= amount;
37+ }
38+ ```
39+ 攻擊方式:
40+
41+ 1 . 攻擊者先存入一些錢。
42+ 2 . 攻擊者寫一個惡意合約,在 receive() 或 fallback() 函數中再次呼叫 withdraw()。
43+ 3 . 當 withdraw() 在第 1 步 call 發送 ETH 時,攻擊者的合約立刻觸發 fallback,再次執行 withdraw()。
44+ 4 . 因為餘額尚未在第 2 步更新(狀態改變太晚),所以檢查依然通過,可以重複領錢。
45+ 5 . 直到合約的錢被領光。
46+
47+ #### 如何防範
48+
49+ ##### 1. CEI Pattern(Checks-Effects-Interactions 模式)
50+ 1 . 檢查條件(Check)
51+ 2 . 更新狀態(Effects)
52+ 3 . 最後與外部互動(Interactions)
53+ ``` solidity=
54+ function withdraw(uint amount) public {
55+ require(balances[msg.sender] >= amount, "Not enough balance");
56+
57+ // 先更新餘額(防止重入)
58+ balances[msg.sender] -= amount;
59+
60+ // 再轉錢
61+ (bool success, ) = msg.sender.call{value: amount}("");
62+ require(success, "Transfer failed");
63+ }
64+ ```
65+
66+ ##### 2. 重入鎖(Reentrancy Guard)
67+ 透過一個 狀態變數 來記錄「現在這個函數是不是正在執行中」。
68+ ``` solidity=
69+ contract ReentrancyGuard {
70+ bool private locked;
71+
72+ modifier noReentrant() {
73+ require(!locked, "Reentrant call");
74+ locked = true;
75+ _;
76+ locked = false;
77+ }
78+ }
79+ // 也可以import OpenZeppelin 提供的 ReentrancyGuard
80+ // import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
81+
82+
83+ contract SecureWithGuard is ReentrancyGuard {
84+ mapping(address => uint256) public balances;
85+
86+ function withdraw() external noReentrant {
87+ uint256 amount = balances[msg.sender];
88+ require(amount > 0, "No balance");
89+
90+ balances[msg.sender] = 0;
91+ (bool success,) = msg.sender.call{value: amount}("");
92+ require(success, "Transfer failed");
93+ }
94+ }
95+ ```
96+
1897# 2025-08-14
1998
2099### 介面 (Interfaces) (接口)
0 commit comments