# 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/ ![](https://i.imgur.com/esl1BRq.png =250x450)![](https://i.imgur.com/4Q8cPwk.png =250x450) ---- ### October? Hacktober… ![](https://i.imgur.com/u0TLWlj.jpg =320x350)![](https://i.imgur.com/wXYGYPA.jpg =400x500) 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>) ---- ## 合約範例 ![](https://i.imgur.com/4YcA2ga.png) ---- ### 如何預防 - Compilier version >= 0.8.0 ![](https://i.imgur.com/7UcOZdZ.png) ---- ##### 當你很確定 overflow/underflow 問題不會發生時可以使用 `unchekced` ```solidity= for (uint256 i = 0; i < 10;) { // Do somethine ... unchecked { i++; } } ``` ---- ### 如何預防 - SafeMath library ![](https://i.imgur.com/BIeohWH.png) --- ## 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 ![](https://i.imgur.com/AlYcXys.png) ---- #### A real world example of uninitialized contract - Parity multisig wallet - 由 Parity Technologies 所開發 - 是當時最著名的多簽實現 ---- #### Parity multisig wallet 在 `WalletLibrary` 合約中的兩個函數 ![](https://i.imgur.com/2xKEuvW.png) ---- ### Oops ![](https://i.imgur.com/TtGtrTW.png) ---- ![](https://i.imgur.com/EsMy7mi.png) - 在 Library 被自殺之後,所有透過 delegatecall 呼叫這個 WalletLibrary 的多簽合約都變成了 No-ops - 多簽錢包中的 50 萬顆 ETH 被鎖在了合約中 ---- ### tx.origin ![](https://i.imgur.com/HejZhOO.png) ---- ### 下面這兩個 `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 ![](https://i.imgur.com/707PTeo.png) ---- ### 如何預防 - 正確的初始化你的合約 - 使用 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? ![](https://i.imgur.com/71G6XiA.png) ![](https://i.imgur.com/BQhIoOJ.png) ---- #### ERC721 `safeTransferFrom` is not safe? ![](https://i.imgur.com/pcDKLKJ.png) ---- ### 會觸發 external call 的方式 - 呼叫其他合約的 function/fallback/receive - `address.call()` - `address.transfer()` - `address.send()` ---- ### A classic example ![](https://i.imgur.com/ImixTlA.png) ---- ### What about this ![](https://i.imgur.com/Vmiu4id.png) ---- ### A real world example ![](https://i.imgur.com/f6TUWew.png =1600x450) ---- ### 重入攻擊原理總結 - 利用未更新的狀態,在 external call 的過程中來攻擊 - 攻擊者可能會重入原本的合約,也可以重入與其他有儲存相關狀態的合約 ---- ### 如何預防 - 了解你要 external call 的對象 - 更新完狀態再去做 external call - Checks - Effects - Interactions ![](https://i.imgur.com/KLvXyIo.png) ---- ### 如何預防 - 使用 [ReentrancyGuard](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol) ![](https://i.imgur.com/a9ex6Mk.png =700x500) --- ## Denial of Service ---- ### Unbounded For loop ![](https://i.imgur.com/g8IpGcp.png) ---- ### External call, again! ![](https://i.imgur.com/gaquv7d.png) --- ## Randomness ---- #### 什麼時候會需要在合約中使用亂數? - 樂透 - 隨機 NFT 盲盒 - 賭場 - ... ---- #### 先來看個沒有那麼安全的亂數 ![](https://i.imgur.com/XPyJvhP.png) ---- #### 用鏈上資訊當亂數種子的問題 - 可以被礦工操縱 - 在同一個區塊中的交易有辦法產出相同的 seed ---- #### 一個猜硬幣的例子 ![](https://i.imgur.com/vhuJfLE.png) ![](https://i.imgur.com/qIWomIm.png) ---- #### 如何安全的產生亂數 - [Chainlink VRF](https://chain.link/vrf)(Verifiable randomness function) - 透過 Oracle 獲取一個安全的亂數 - 需要支付 $LINK 代幣 - [RANDAO](https://github.com/randao/randao) - 透過多人合作共同產生出一個亂數 --- ## Ethernaut ---- ![](https://i.imgur.com/i6qYCxd.png) 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}]"}
    972 views