加密專案智能合約審計逐步指南

智能合約審計是一種結構化的嘗試,旨在發現合約可能出現的故障、濫用或以用戶意想不到的方式被控制的情況。它不同於運行一次掃描器、查看審計徽章或確認原始程式碼已通過驗證。在將重要資金委託給已部署的 EVM 合約或程式碼庫之前,請使用以下工作流程進行審查。

重要提示:本指南僅提供實用的審查框架,並非保證專案安全,亦不構成投資建議。具有重大價值的生產環境協議應由經驗豐富的安全專家進行獨立審查。本指南中的介面樣式圖片僅供參考,不應被視為任何特定項目或部署的證據。

審計清單概覽

步主要問題有用的證據
1. 範圍我審核的是否正是用戶所撥打的電話所要查看的合約?位址、鏈、字節碼、代理和實現
2. 入口每個來電者可以做什麼?公共/外部函數、狀態變更、呼叫圖
3. 自動化哪些顯而易見的模式值得關注?編譯器輸出、Slither 偵測結果、偵測器分類
4. 手動安全調用序列能否打破既定假設?外部呼叫、重入、回調、故障處理
5. 邏輯在特殊情況下,會計處理是否仍然正確?算術運算、四捨五入、費用、限額、狀態轉換
6. 特權誰能改變或停止這個系統?角色、所有者、管理員金鑰、代理、初始化程序
7. 測試行為能否在意外的輸入和序列中保持不變?單元測試、模糊測試、不變式測試和叉形測試
8. 報告其他人能否復現並重新測試該結果?發現、影響、證據、修復和重新測試狀態

步驟 1:確認範圍和已部署的工件

通用合約驗證螢幕,顯示以太坊主網、合約位址、編譯器版本、已驗證原始碼狀態以及完全匹配的字節碼。
合約驗證視圖,顯示分析前需要記錄的網路、位址、編譯器版本和字節碼匹配檢查。

首先要確保鍊和位址完全正確。記錄部署位址、交易雜湊、區塊號碼、編譯器版本、最佳化器設定、建構函式參數,以及團隊確認已部署的提交或版本。一個專案可能存在多個地址,分別用於代幣、路由器、金庫、代理、實作、預言機或測試部署。查閱錯誤的地址沒有任何實際意義。

檢查瀏覽器驗證的原始程式碼是否與已部署的字節碼一致。驗證的作用在於允許您檢查原始程式碼和應用二進位介面 (ABI),但它僅是一種身份驗證,並不能證明業務邏輯的安全性。如果合約可升級,請確定代理商及其目前實作。從代理程式的文檔機製或瀏覽器資訊中讀取實作位址,然後確認實作是否是您打算審查的實作。 Etherscan 的官方 Foundry 驗證指南詳細記錄了新合約和現有合約的驗證過程。

同時明確邊界。包括導入的庫、繼承的合約、連結的庫、已部署的輔助合約、預言機適配器、從用戶接收的代幣以及特權鏈下元件。記錄哪些內容超出範圍以及原因。這可以避免將範圍狹窄的審查誤認為是對整個系統的審查。

步驟 2:建立入口點和資產地圖

通用原始碼審查視窗列出了公共和外部 Solidity 函數,以及 ERC-20 風格的合約實作。
在審查人員追蹤其狀態變化之前,對公共入口點和外部入口點進行功能清單劃分。

列出所有公用函數和外部函數,包括繼承函數、回退函數或接收處理程序。對於每個函數,記錄它是否能夠:

  • 轉移本地貨幣或代幣;
  • 鑄造、焚燒、借貸、清算或竄改帳目;
  • 更改預言機、費用、限額、角色、暫停狀態或實現;
  • 進行外部呼叫、委託呼叫或底層呼叫;或
  • 讀取另一個狀態改變函數所依賴的資料。

然後繪製資產和信任邊界圖。追蹤用戶從儲存到提現的整個過程,包括定價和份額計算。識別呼叫者提供的每個位址和從儲存載入的每個位址。詢問哪些值被認為是誠實的:預言機、令牌、橋樑訊息、保管員、回調接收器或管理員。最高價值的審查目標是結合了使用者控制的輸入、特權狀態、算術運算和外部呼叫的函數。

步驟 3:編譯並執行靜態分析

通用終端機顯示命令“slither dot”,並發現重入性問題、未檢查的底層呼叫以及 ERC-20 介面問題。
靜態分析運行可以快速發現潛在問題,但仍需根據實際程式碼和威脅模型進行確認。

使用指定的 Solidity 版本、相依性版本、最佳化器配置和目標鏈假設重現專案建置。將編譯器警告視為程式碼審查要點,而非無關緊要的雜訊。 Solidity 的安全建議特別強調認真對待警告、保持契約清晰易懂,並檢查已知的編譯器問題。當編譯器版本或受影響的程式碼模式與此相關時,請查閱官方已知的 Solidity 編譯器錯誤清單。

對於 Hardhat、Foundry 或類似項目,請從專案根目錄執行 Slither。其官方文件將該工具描述為 Solidity 和 Vyper 靜態分析器,並給出了常用命令:

slither .

保存輸出結果,並根據影響程度和置信度對每個結果進行分類。重點關注涉及任意令牌發送、未受保護的升級、重入、未經檢查的回傳值、危險的委託呼叫、tx.origin、弱隨機性和錯誤介面的發現。檢測器可能會報告誤報,遺漏專案特定的經濟缺陷,或標記在其他地方有意限制的程式碼。靜態分析可以縮小搜尋範圍,但不能取代人工推理。 Slither程式碼庫和文件還列出了入口點、授權、呼叫圖和合約摘要的列印工具,有助於組織審查工作。

步驟 4:手動追蹤外部呼叫和重入

通用程式碼審查視窗突出顯示餘額更新之前的低階值呼叫和高危重入審查說明
在餘額更新之前會突出顯示外部調用,這說明了審核人員應該在每個提款路徑中測試的排序問題。

對於每個外部調用,都要停止並追蹤調用前、調用期間和調用後的狀態。被呼叫方可能是惡意合約、帶有鉤子的代幣、回呼接收器,或其他會更改共享依賴項的協定。 Solidity 文件解釋說,與其他合約的互動可能會將控制權交給該合約,並推薦使用「檢查-影響-互動」模式:首先進行驗證,其次更新當前合約的狀態,最後進行外部互動。

不要將搜尋範圍局限於顯而易見的以太幣轉帳。檢查 ERC-777 風格的鉤子、ERC-1155 回呼、閃電貸回呼、任意路由、預言機呼叫以及透過繼承函式庫進行的呼叫。檢視跨函數和跨合約的重入性:回呼可能會進入讀取中間狀態的不同函數。確認每個底層呼叫都會檢查其成功結果並正確處理返回值。詢問失敗的收款人是否可以永久阻止提現或導致循環。

針對每個可能出現的問題,記錄一個特定的攻擊序列。例如:攻擊者存入資金,發動提款請求,收到回調,再次發動提款請求,然後才允許第一次提款請求完成。如果由於某個特定的不變式或保護機制導致該序列無法成功執行,請記錄下原因。這樣可以使結論具有可審計性,而非僅僅是推測。

步驟 5:測試算術和業務不變性

通用審計清單,包含整數邊界、捨去、股價計算和零值邊界情況的檢查。
算術和業務邏輯檢查清單突顯了普通正常路徑測試經常忽略的邊界情況。

檢查每個單位和轉換的含義:例如 wei 與以太幣、代幣小數、基點、份額與資產、有符號值以及時間單位。遵循舍入方向。如果除法運算的捨入結果有利於存款人、借款人、清算人或費用接收人,則重複進行此類運算可能會造成價值損失。在進行除法運算之前,請檢查乘法運算、最小和最大金額、費用上限、過時價格、零供應量、零餘額以及第一個存款人或最後一個取款人。

Solidity 0.8 及更高版本通常會偵測算術溢出和下溢,但unchecked程式碼區塊內的程式碼會故意改變這種行為。如果限制設計不當,受檢算術也可能導致協議回溯或無法使用。需要測試兩種結果:資料被盜或記帳錯誤,以及由於無法處理的值而導致的拒絕服務。

在將不變量轉換為測試案例之前,請先用簡單易懂的語言編寫它們。例如,「總份額對應於指定舍入規則下的資產」、「用戶提取的金額不能超過其記錄的認領金額」、「代幣總供應量等於適用該模型的餘額之和」以及「手續費不能超過其配置的上限」。請將儲存餘額與實際代幣餘額進行比較,因為代幣可以直接發送到合約,或者其行為可能與假定的 ERC-20 實作有所不同。

步驟 6:審查權限和可升級性

通用權限和升級能力螢幕,顯示擁有者、管理員、暫停者、升級者角色以及代理到實現的關係
權限審查應將每個角色與其位址、允許的操作、轉移過程和升級路徑關聯起來。

建構權限矩陣。針對每項管理功能,明確其所需角色、目前持有者、轉移機制、延遲、多重簽章或治理控制以及緊急處理措施。尤其要注意代幣的鑄造、暫停、費用變更、預言機源變更、資金救援、代碼升級以及可信任代幣或路由器地址變更等操作。 OpenZeppelin 的存取控製文件區分了簡單的所有權和基於角色的權限,並將最小權限原則描述為一種有效的安全實踐。

區分“程式碼允許管理員執行此操作”和“任意使用者都可以執行此操作”。前者可能構成明確的治理或託管風險;後者則構成授權漏洞。驗證角色檢查是否涵蓋所有敏感路徑,包括可從公用函數存取的內部輔助函數。檢查預設管理員是否可以授予自己或其他使用者額外的權限,以及所有權轉移是否可能意外傳送到無效位址。

對於代理,請審查初始化程序、實現授權、升級延遲、儲存佈局以及回滾或應急計劃。 OpenZeppelin 的可升級合約指南解釋了為什麼建構函式不初始化代理程式儲存、為什麼必須保護初始化程序、為什麼實作不應保持未初始化狀態,以及為什麼更改儲存順序或類型會導致升級失敗。請將代理管理金鑰視為協定安全邊界的一部分,而不是實作細節。

步驟 7:使用模糊測試、不變量測試和分支測試來檢驗系統效能。

通用測試儀表板顯示通過的模糊測試、通過的不變式測試以及反例調用序列
通過的行動是有用的證據,而反例追蹤則準確地顯示了哪個序列需要調查。

先執行單元測試以驗證預期行為,然後新增未經授權的呼叫者、零值、最大值、過期簽名、過時的預言機資料、傳輸失敗和重複操作的負面測試。使用模糊測試方法測試輸入,而不是只測試少數精心挑選的數字。如果設計允許回調,則應包含多個參與者和惡意接收者合約。

對於在多次隨機呼叫後必須保持為真的屬性,請使用不變性測試。 Foundry的不變性測試文件描述了隨機序列、模糊輸入、運行、深度、目標合約和目標發送者。配置處理程序,使呼叫具有意義;如果每次模糊存款都因為測試參與者沒有代幣而回滾,則通過不變性測試可能僅僅意味著沒有有效的狀態變化。

如果可能,請使用目標網路的分支來測試已部署的位址、目前配置、代幣行為和代理路由。除非使用隔離的本機分支,否則請確保分支測試資料安全且唯讀。盡量減少每次失敗的測試序列,並保留反例、呼叫者地址、區塊上下文、餘額和相關儲存值。通過的測試僅能證明已測試路徑的有效性,而非所有可能路徑的有效性。

步驟 8:寫下可以修復和重新測試的發現

一般審計報告,依嚴重程度顯示稽核結果,風險狀態分為未解決、已修復及已接受三種,並附有複測清單。
一份有用的報告會將嚴重程度和狀態與證據、具體的修復方案和複測條件連結起來。

每個問題僅記錄一筆結果。一項實際調查結果應包含:

  • 標題和位置:合約、功能、文件和行或程式碼參考。
  • 影響:哪些東西可能被偷走、被凍結、被膨脹、被繞過或弄錯。
  • 前提條件:所需的權限、餘額、時間或配置。
  • 複製:一段簡短的交易序列、測試、追蹤或證明。
  • 建議:對程式碼或操作進行具體更改,但需權衡利弊。
  • 狀態:開放、已修復、已緩解、風險已接受或無法重現。
  • 複測:確認結果的精確測試或觀察。

嚴重性評估應反映實際影響和可利用性,而非程式碼模式看起來多麼令人擔憂。解釋假設。底層呼叫可能在強不變性的保護下是安全的;看似普通的參數更改,如果控制預言機或升級,則可能至關重要。修復後,檢查差異,重新執行相關測試,重新執行整個測試套件,並檢查是否有回歸問題。如果已部署的位址已升級或更改,則重新測試實際的鏈上實作和配置。

避免常見的審計錯誤

  • 「原始碼已經過驗證,所以是安全的。」驗證只是確認原始碼和字節碼之間的對應關係,並不驗證設計本身。
  • 「掃描器未發現任何問題,因此不存在漏洞。」工具在識別已知模式方面最為有效,而經濟和跨合約缺陷通常需要人工分析。
  • 「該專案已有稽核報告,因此目前部署已涵蓋在內。」請比較報告中的提交記錄、範圍、部署位址、修復程序和升級歷史記錄。
  • 「模糊測試通過,因此該不變量是正確的。」首先確認該不變量表達了預期的經濟屬性,並且處理程序達到了有意義的狀態。
  • 「管理員權限並非安全問題。」這可能是出於信任的考慮,但用戶應該能夠看到誰可以鑄幣、暫停、更改參數或升級。

在相信結果之前,請先進行最後的自我檢查。

你應該能夠對以下問題回答「是」:

  • 我是否記錄了確切的鏈、地址、字節碼、代理、實現和構建設定?
  • 我是否已清點所有可能改變狀態的入口點及其可能影響的資產?
  • 我是否正確編譯了文件、檢查了警告訊息並對自動發現的問題進行了分類?
  • 我是否追蹤了每一個外部呼叫、回調、底層呼叫和故障路徑?
  • 我測試過捨入、限制、零值、過時資料和重複操作嗎?
  • 我是否已映射所有特權角色、金鑰、延遲、初始化程序和升級路徑?
  • 我是否保留了有意義的模糊集合和不變的反例?
  • 獨立審閱者能否重現每項發現並驗證每項修復?

如果任何答案為“否”,則應將審計標記為“不完整”,並說明缺失的證據。明確的限制比模糊的「安全」結論更有用。智慧合約安全是一個持續的過程:每一次升級、依賴項變更、新的整合以及權限變更都可能產生新的審查邊界。

留下評論

DeFi流動性池中的無常損失是什麼?如何減少無常損失?

DeFi流動性池中的無常損失是什麼?如何減少無常損失?

了解什麼是無常損失,為什麼 AMM 流動性池會產生無常損失,費用如何影響收益,以及在提供流動性之前降低風險的實用方法。

The Psychology of HODLing: How to Survive Crypto Market Crashes

The Psychology of HODLing: How to Survive Crypto Market Crashes

Learn why crypto crashes trigger bad decisions, which HODLing myths to avoid, and how to build a disciplined plan for volatility without blindly holding forever.

網路擁塞問題:為什麼您的加密貨幣轉帳處於待處理狀態以及該如何解決

網路擁塞問題:為什麼您的加密貨幣轉帳處於待處理狀態以及該如何解決

您的加密貨幣轉帳是否正在等待處理?了解如何識別擁塞情況、檢查交易雜湊值、選擇等待或替換,以及避免代價高昂的錯誤。

代幣與通證:加密貨幣中二者有何不同?

代幣與通證:加密貨幣中二者有何不同?

了解加密貨幣代幣與普通代幣的區別,包括網路所有權、費用、安全性、控制權、使用案例,以及哪種資產適合不同的需求。

管理加密貨幣投資組合風險:如何配置您的資產

管理加密貨幣投資組合風險:如何配置您的資產

學習如何根據風險承受能力、時間範圍、多元化、託管、流動性和再平衡來分配加密貨幣——而無需依賴一刀切的公式。

加密專案智能合約審計逐步指南

加密專案智能合約審計逐步指南

學習如何逐步審核加密專案的智慧合約,從驗證部署和映射權限到測試邏輯、升級和修復。

The Ultimate Guide to Building a Long-Term Crypto Holding Portfolio

The Ultimate Guide to Building a Long-Term Crypto Holding Portfolio

Build a long-term crypto holding portfolio with a risk-first framework for allocation, asset selection, custody, buying discipline, rebalancing, records, and scam avoidance.

鏈上分析入門:如何追蹤巨鯨錢包和智慧資金

鏈上分析入門:如何追蹤巨鯨錢包和智慧資金

學習如何讀取鏈上數據、追蹤巨鯨錢包、評估智慧貨幣標籤,以及在對錢包活動採取行動之前,將可驗證的區塊鏈事實與推論區分開來。

加密貨幣期貨中的「保證金不足」錯誤:其意義及解決方法

加密貨幣期貨中的「保證金不足」錯誤:其意義及解決方法

了解為什麼加密貨幣期貨平台會顯示「保證金不足」錯誤,如何診斷原因,安全地解決問題,並在進行下一次交易之前避免保證金問題。

幣安 Launchpad 和 Launchpool:如何參與並賺取新代幣

幣安 Launchpad 和 Launchpool:如何參與並賺取新代幣

了解幣安 Launchpad 和 Launchpool 的運作方式、如何查看資格、安全加入、追蹤獎勵,以及了解限制和風險。