本實踐旨在幫助開發者更好地理解 Sui 智慧合約的安全風險,並提供實用的解決方案。

作者:Victory!,慢霧安全團隊

  編輯:Lisa,Liz

Sui 作為一個新興的高性能區塊鏈平臺,具備多項創新技術和獨特性,同時專注於為各種應用場景提供快速、安全的交易體驗。 關於 Sui 的基礎知識可查閱探索 Sui:高性能背後的技術與合約安全。 與其他區塊鏈常用的程式設計語言(如 Solidity)有所不同,Sui 使用 Move 語言,在一定程度上能解決 Solidity 高發的漏洞問題,如重入攻擊、整數溢出、雙花、DoS 攻擊和編譯器問題,但避免不了開發者在代碼中引入錯誤。 因此,開發者在使用時需要瞭解並注意一些獨特的功能或特性,確保智慧合約的安全性。

慢霧安全團隊整合吸收了 Sui 社區分享的安全開發實踐,並結合自身多年積累的安全審計經驗,發佈 Sui - Move 合約審計入門,旨在幫助開發者更好地理解 Sui 智慧合約的安全風險,並提供實用的解決方案,以降低潛在的安全威脅。

由於篇幅限制,本文僅羅列 Sui - Move 合約審計入門的部分內容,歡迎大家在 GitHub 上 Watch、Fork 及 Star:https://github.com/slowmist/Sui-MOVE-Smart-Contract-Auditing-Primer/blob/main/README_CN.md。

  關鍵知識點

 1. 模組聲明和可見性

1.1 “public(friend)” 函數(在最新的 Sui 版本中 “public(friend)” 被替換成 “public(package)”)

定義:用於聲明函數,使其只能被指定的友元模組訪問。 這提供了更細粒度的訪問控制,介於 “public” 和 “private” 之間。

  範例:

 1.2 “entry” 函數

定義:「entry」函數是模組的入口點,允許從事務塊中直接調用。 參數必須來自事務塊的輸入,不能是塊中先前事務的結果或被修改的數據。 此外,「entry」函數只能返回具有「drop」能力的類型。

  範例:

 1.3 “public” 函數

定義:「public」函數可以從事務塊和其他模組調用,適合外部交互。 在參數和返回值上沒有和「entry」函數一樣的限制,通常用於將功能暴露給外部。

  範例:

 2. 物件管理

 2.1 物件的唯一性

定義:每個 Sui 物件都有唯一的 “objID”,確保了對象在鏈上的唯一性。

 2.2 包裝和解包

  定義:

  • 直接包裝:將一個 Sui 對象作為另一個物件的欄位,解包時必須銷毀包裝物件。
  • 對象包裝:包裝后的對象成為另一物件的一部分,不再獨立存在。 解包後物件的 ID 不變。

 2.3 自定義轉移策略

定義:使用 “sui::transfer::transfer” 定義自定義轉移策略,針對具有 “store” 能力的物件,可以通過 “sui::transfer::p ublic_transfer” 創建。

 2.4 對象的屬性

定義:Sui 對象的屬性包括「copy」“ drop”

 2.5 對象的許可權檢查

  •   位址擁有的物件

定義:由特定位址(帳戶位址或物件 ID)擁有的物件,只有物件的所有者可以訪問和操作這些物件。

  •   不可變物件

定義:不可變對象無法被修改或轉移,任何人都可以訪問。 適用於需要全域訪問但不需要修改的數據。

  •   共享物件

定義:共享物件可以被多個使用者訪問和操作,適用於去中心化應用等場景,但由於需要共識,操作成本較高。

  •   包裹的物件

定義:包裝物件是將一個物件嵌入另一個對象,包裝后的物件不再獨立存在,必須通過包裝物件訪問。

 3. 安全性檢查

 3.1 數值溢出檢查

 Sui 的智慧合約預設進行數值溢出檢查。

 3.2 重入檢查

所謂的重入攻擊是在一筆正常的合約調用交易中,被插入一筆非預期的(外部)調用,從而改變整體的業務調用流程,實現非法獲利的行為。 涉及到外部合約調用的位置,都可能存在潛在的重入風險。 目前的重入問題我們可以分為三類:單函數重入、跨函數重入以及跨合約重入。 Move 語言的一些特性為防範重入攻擊提供了天然的保護:

  • Move 中無動態調用,其外部調用都需先通過 use 進行導入,即外部調用都是預期、確定的。
  • 無 Native 代幣轉帳觸發 Fallback 功能。
  • 在 Move 中,資源模型確保資源一次只能由單個執行上下文訪問。 這意味著如果函數執行未完成,則在執行完成之前其他函數無法訪問同一資源。

  審計入門

 1. 溢出審計

說明:Move 進行數學運算時會進行溢出檢查,運算溢出的話交易將失敗。 但需要注意的是,對於位運算,Move 並不會進行溢出檢查。

定位:尋找代碼中進行位運算的位置,檢查是否有溢出風險。

 2. 算術精度誤差審計

說明:Move 中沒有浮點類型。 因此,在進行算術運算時,如果運算結果需要以浮點數表示,可能會產生精度誤差。 雖然精度誤差在某些情況下難以完全避免,但可以通過優化和合理設計來減輕其影響。

定位:審查代碼中所有涉及算術運算的部分,特別是可能產生精度誤差的計算,確保這些運算不會對合約邏輯或數值準確性產生負面影響,並提出優化建議以減輕精度誤差。

 3. 條件競爭審計

說明:Sui 中的驗證者也可以對使用者提交的交易進行排序,因此在審計中我們仍需要注意在同一個區塊中對交易進行排序而獲利的問題。

定位:

  •   是否有對函數調用前合約的數據狀態進行預期管理。
  •   是否有對函數執行中的合約數據狀態進行預期管理。
  •   是否有對函數調用后的合約數據狀態進行預期的管理。

 4. 存取控制審計

說明:合約中的某些關鍵函數應僅限於內部調用,例如能夠直接更新使用者存款數額的函數。 如果這些函數不慎對外部開放,可能繞過許可權控制,導致安全漏洞,甚至引發資產損失。 因此,必須嚴格設置訪問許可權,確保只有授權角色或模組可以調用這些函數,或者確保函數只能在內部使用。

定位:需要檢查所有函數的訪問控制設置,特別是那些不應該對外公開的函數,確保它們只能在內部調用。 如果發現不應暴露的函數介面已經公開,必須標記為高風險並提出修正建議。

 5. 物件管理審計

說明:在 Sui 中,物件可以被轉換為共享物件(Shared Object),這意味著對象的訪問許可權可能從私有變為公共。 因此,需要對所有使用的對象進行詳細審查,明確每個對像是靜態的還是共用的。 特別要注意是否有對象被錯誤地從私有物件轉換為共用對象,這樣可能導致未經授權的使用者訪問這些對象,帶來潛在的安全風險。

定位:整理並分析模組中所有涉及的對象,檢查對象的類型和許可權設置,確保該對象的許可權與業務需求匹配。 如果發現私有對象被錯誤地轉換為共用物件,必須標記為潛在風險並提出修正建議。

 6. Token 消耗審計

說明:Sui 的代幣模型與其他鏈的代幣模型有所不同。 Sui 允許物件持有代幣,並且代幣物件可以嵌套在其他物件中,還可以進行拆分。 因此,在涉及代幣消耗的場景中,需要特別關注代幣的管理和流轉,以避免安全問題或意外損失。

定位:

  •   檢查消耗的金額是否準確。
  •   檢查代幣物件是否已經正確轉移。
  •   檢查代幣的拆分和合併是否合理。
  •   檢查代幣與對象的綁定。

 7. 閃電貸攻擊審計

說明:Sui 的 Move 也有閃電貸的用法(Hot Potato)。 用戶可以在一筆交易中借取大量的資金任意使用,只需在這筆交易內歸還資金即可。 惡意使用者通常使用閃電貸放大自身的資金規模進行價格操控等大資金攻擊。

定位:分析協定本身的演算法(獎勵、利率等)及預言機依賴是否合理。

 8. 許可權漏洞審計

說明:在 Sui 的 Move 合約中,許可權漏洞這部分和業務的需求以及功能設計關係較大,所以遇見較為複雜的 Module 時,需要和專案方確認各個方法的調用許可權(這裡的許可權一般是指函數的可見性和函數的調用許可權)。

定位:

  • 檢查和確認所有函數方法的可見性及調用許可權,在專案評估階段就需要專案方提供設計文檔,審計時根據設計文檔中的描述從而確認許可權。
  • 梳理專案方角色的許可權範圍,如果專案方角色的許可權會影響用戶的資產,則存在許可權過大的風險。
  • 分析對外函數裡面傳遞進去的對象是什麼類型,如果是一些特權函數,則必須要有一些特權對象參與。

 9. 合約升級的安全審計

說明:在 Move 中,外部模組通過 use 關鍵字導入。 需要注意的是,Sui 的合約是可升級的,但發佈的合約包(package)是不可變的物件,一旦發佈就無法撤回或修改。 合約升級的本質是通過在新的位址上重新發佈更新的合約,並將舊版本合約的數據遷移至新的合約中。 因此,合約升級過程中需要特別注意:

  • “init” 函數:“init” 函數僅在合約第一次發佈時執行,後續合約升級時不會再次觸發。
  • 升級合約不會自動更新依賴:如果合約包依賴於外部包,當外部包升級時,合約包不會自動指向升級后的合約位址。 因此,需要手動升級自己的合約包以指定新的依賴項。

定位:需要對合約升級過程中數據遷移的邏輯進行詳細檢查,確保遷移操作安全、準確,並避免遺漏重要數據或依賴更新的問題。

 10. 外部調用安全審計

說明:與外部模組使用審計項相同,由於 Move 中進行外部調用需要先將外部模組導入,因此理論上外部調用的結果都是開發人員所預期,所需主要的是外部模組的穩定性。

  定位:需要對外部引入的庫進行檢查。

 11. 傳回值的檢查

說明:和其他智慧合約語言類似,在 Move 合約中,需要對某些函數的返回值進行檢查。 如果忽略了對這些返回值的處理,可能會導致關鍵邏輯沒有正確執行,進而引發安全問題。

定位:需要檢查代碼中每個函數調用的返回值,特別是那些涉及外部調用或重要狀態更新的函數。 如果返回值未被處理或驗證,可能會導致不可預期的行為,應該標註為潛在風險點。

 12. 拒絕服務審計

說明:拒絕服務(DoS)攻擊可能由代碼邏輯錯誤、相容性問題或其他安全漏洞引發,導致智慧合約無法正常運行。 此類問題可能影響合約的可用性,甚至使其完全癱瘓。

定位:

  • 重點檢查業務邏輯的健壯性,確保在各種情況下都能正常執行,不會因錯誤或漏洞導致合約中斷。
  • 關注與外部模組交互的部分,確保其相容性,以防止由於外部依賴問題導致的服務中斷。

 13. Gas 優化審計

說明:與乙太坊一樣,Sui 也有 Gas 機制,任何模組腳本調用都會消耗 Gas。 因此對一些冗長且高複雜度的代碼進行優化是有必要的。

定位:

  •   涉及到複雜的調用看是否可以解耦。
  • 涉及到高頻率的調用看是否可以優化函數內部執行的效率。

 14. 設計邏輯審計

說明:設計邏輯審計的重點是檢查代碼中的業務流程和實現,確認是否存在設計缺陷或與預期不符的情況。 代碼實現如果與預期邏輯不一致,可能會導致意外的行為或安全風險。

定位:

  • 根據不同角色的許可權和作用範圍,梳理業務流程中的可能調用路徑。
  • 確定每個業務流程所涉及的數據範圍,確保數據的操作與業務設計一致。
  • 將實際的調用路徑與預期的業務流程進行比較,識別並分析任何可能導致非預期結果的調用情況。

15. 其他

  未在上述表述中體現的內容。

寫在最後

對開發者而言,遵循這些最佳實踐,可以有效提升智慧合約的安全性,減少潛在的安全風險。 希望這一最佳實踐可以説明更多的開發者打造安全可靠的智慧合約,推動區塊鏈技術的健康發展。

參考:

[1] https://intro.sui-book.com/

[2] https://docs.sui.io/

[3] https://move-dao.github.io/move-book-zh/introduction.html

免責聲明:作為區塊鏈資訊平臺,本站所發佈文章僅代表作者及嘉賓個人觀點,與 Web3Caff 立場無關。 文章內的資訊僅供參考,均不構成任何投資建議及要約,並請您遵守所在國家或地區的相關法律法規。