# Smart Contract Security 101
slides: https://hackmd.io/@BillHsu/sec101
---
## About me
- Bill
- Previously stake.fish, Binance research, ...
- 區塊鏈安全研究員 @ Amber Group
- 區塊鏈課程導師 @ AppWorks School
---
## Today's Outline
- 為什麼區塊鏈安全很重要?
- 常見的安全問題
- Arithmetic
- Access control
- Reentrancy
- DoS
- Randomness
- Ethernaut
---
## 為什麼區塊鏈安全很重要?
----
### REKT leaderboard
https://rekt.news/leaderboard/

----
### October? Hacktober…

Source: https://twitter.com/Beosin_com
----
### 所以為什麼區塊鏈安全很重要?
- 金融應用多
- 去中心化、不可篡改
- 匿名性
---
## Arithmetic
----
## Solidity 中型別的值域
- uint8, uint16, uint24, …, uint256
- For example:
- uint8 has a range of 0 to 2 ** 8 - 1
- uint256 has a range of 0 to 2 ** 256 - 1
----
## Overflow and Underflow
- uint8(2 ** 8 - 1) + 1 的結果是多少?
- 11111111<sub>2</sub> + 1<sub>2</sub> = 100000000<sub>2</sub>
- uint8(100000000<sub>2</sub>) = uint8(0)
- uint8(0) - 1 的結果是多少?
- 0<sub>2</sub> - 1<sub>2</sub> = 11111….1111<sub>2</sub>
- uint8(11111….1111<sub>2</sub>) = uint8(11111111<sub>2</sub>)
----
## 合約範例

----
### 如何預防 - Compilier version >= 0.8.0

----
##### 當你很確定 overflow/underflow 問題不會發生時可以使用 `unchekced`
```solidity=
for (uint256 i = 0; i < 10;) {
// Do somethine
...
unchecked {
i++;
}
}
```
----
### 如何預防 - SafeMath library

---
## Access Control
----
### 常見的 access control 問題
- Function visibility
- Private/internal function 不小心被寫成 public/external
- Priviledged function
- 未初始化/未正確初始化
- 缺少 onlyOwner modifier
- ...
- 誤用 tx.origin
----
#### A real world example of using wrong visibility

----
#### A real world example of uninitialized contract
- Parity multisig wallet
- 由 Parity Technologies 所開發
- 是當時最著名的多簽實現
----
#### Parity multisig wallet
在 `WalletLibrary` 合約中的兩個函數

----
### Oops

----

- 在 Library 被自殺之後,所有透過 delegatecall 呼叫這個 WalletLibrary 的多簽合約都變成了 No-ops
- 多簽錢包中的 50 萬顆 ETH 被鎖在了合約中
----
### tx.origin

----
### 下面這兩個 `onlyOwner` 有什麼差?
```solidity=
modifier onlyOwner {
require(msg.sender == owner, "Not owner");
}
```
```solidity=
modifier onlyOwner {
require(tx.origin == owner, "Not owner");
}
```
----
### 別亂用 tx.origin
如果 `owner` 不小心與一個惡意合約互動了,惡意合約就能夠通過使用 `tx.origin` 版本的 onlyOwner

----
### 如何預防
- 正確的初始化你的合約
- 使用 Ownable or AccessControl 等 library 來管理合約中有權力的地址和驗證權限
- 撰寫測試確保你沒有粗心
---
## Reentrancy
----
### External call can be dangerous
- 在 external call 的過程中,執行流的控制權會從一個合約轉移給另一個和約
```solidity=
function sendToken(address receiver) public {
token.transfer(receiver, 100);
// ...
}
```
----
### External call can be dangerous
- 向惡意合約發起 external call 時,惡意合約可能會做一些你沒有想到的事情
- 再次呼叫你的合約(重入攻擊)
- 呼叫其他的合約
- 向非惡意的合約發起 external call 時,在過程中惡意合約還是有可能得到控制權
----
#### ERC721 `safeTransferFrom` is not safe?


----
#### ERC721 `safeTransferFrom` is not safe?

----
### 會觸發 external call 的方式
- 呼叫其他合約的 function/fallback/receive
- `address.call()`
- `address.transfer()`
- `address.send()`
----
### A classic example

----
### What about this

----
### A real world example

----
### 重入攻擊原理總結
- 利用未更新的狀態,在 external call 的過程中來攻擊
- 攻擊者可能會重入原本的合約,也可以重入與其他有儲存相關狀態的合約
----
### 如何預防
- 了解你要 external call 的對象
- 更新完狀態再去做 external call
- Checks - Effects - Interactions

----
### 如何預防
- 使用 [ReentrancyGuard](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol)

---
## Denial of Service
----
### Unbounded For loop

----
### External call, again!

---
## Randomness
----
#### 什麼時候會需要在合約中使用亂數?
- 樂透
- 隨機 NFT 盲盒
- 賭場
- ...
----
#### 先來看個沒有那麼安全的亂數

----
#### 用鏈上資訊當亂數種子的問題
- 可以被礦工操縱
- 在同一個區塊中的交易有辦法產出相同的 seed
----
#### 一個猜硬幣的例子


----
#### 如何安全的產生亂數
- [Chainlink VRF](https://chain.link/vrf)(Verifiable randomness function)
- 透過 Oracle 獲取一個安全的亂數
- 需要支付 $LINK 代幣
- [RANDAO](https://github.com/randao/randao)
- 透過多人合作共同產生出一個亂數
---
## Ethernaut
----

https://ethernaut.openzeppelin.com/
----
- Arithmetic: Token
- Access control: Telephone
- Reentrancy: Re-entrancy
- DoS: King
- Randomness: Coin Flip
---
# Thank you
Telegram: @bbbbill
---
{"metaMigratedAt":"2023-06-17T15:08:04.356Z","metaMigratedFrom":"Content","title":"Smart Contract Security 101","breaks":true,"contributors":"[{\"id\":\"6ddadf22-202b-4ee5-8bd3-efc0465c5ecd\",\"add\":6711,\"del\":1463}]"}