詳解DeFi協議智能合約漏洞:4大分類與38種情況

本文作者爲WeBlock CTO Abba Garba,並由HAO翻譯。

區塊鏈是一種新型的分佈式系統體系,它使用P2P對等網絡通信,區塊存儲,分佈式算法共識和加密算法來防止篡改。

從本質上講,區塊鏈可以看作是由所有網絡節點共同維護的分佈式數據庫。與傳統的分佈式數據庫相比,區塊鏈由於具有完整的數據備份,開放透明的網絡,無法篡改,完整的信息可追溯性和弱信任模型,因此更適合對分散式信任有明確要求的應用場景。

特別是典型的區塊鏈應用場景包括數字支付,產品可追溯性,版權保護,供應鏈財務等。在區塊鏈系統中,智能合約在實施分散式應用部署和擴展應用的功能方面發揮着極其重要的作用。

區塊鏈系統與傳統應用程序相比,在區塊鏈系統架構上運行的智能合約具有開放性和透明性,執行性,不可篡改且不依賴第三方的特點,可以滿足各種去中心化應用場景的需求,包括近年來發展迅速的去中心化金融(Defi)項目。

截至2021年1月15日,去中心化金融(DeFi)以超過45億美元的資本成爲了成功的金融範例,它利用基於區塊鏈的智能合約來確保其完整性和安全性。

去中心化金融是一個新的發展領域,用於交換,借出或借用令牌。通常,這些指令由智能合約(而不是單個集中的法人或個人)調節和/或由多方,分散式治理機制(例如DAO)控制的``收益''或收入流。去中心化金融(DeFi)—在現有區塊鏈平臺之上逐漸興起。

這個新領域的組成部分包括那些與貸款,資產交易和衍生品市場有關的部分。作爲去中心化的應用,智能合約管理着大量的數字資產,從而也使其容易受到各種攻擊。

本文將從三個維度具體闡述了智能合約安全性問題:首先,由於以太坊體系結構每一層的漏洞導致的智能合約安全性。其次,也會探討DeFi和智能合約近期出現的各種攻擊。

最後還將探討現有的可行性工具以及來其他的有效實踐如何最大限度地減少此類攻擊。


以太坊架構不同層的智能合約漏洞


以太坊架構概述

在探討智能合約漏洞之前,我們先簡單概述下有關以太坊智能合約架構。

區塊鏈網絡能部署並自動執行編程腳本任務。這些程序稱爲智能合約,用於定義在交易期間調用的自定義功能和規則。基於智能合約的區塊鏈技術已被應用到各種行業中,例如金融,供應鏈管理,醫療保健能源和政府服務。

只有特定的區塊鏈平臺支持智能合約:以太坊是第一個支持智能合約的。其他區塊鏈平臺(例如EOS,Lisk,比特幣和Hyperledger Fabric)兼容於部署和執行智能合約。

一種稱爲Solidity的腳本類型語言用於在以太坊平臺中開發智能合約。在這一部分中,我們介紹了以太坊平臺上智能合約實施的相關安全漏洞。智能合約可以持有和管理相應的功能Credit(地址){可能價值數千美元的大量虛擬貨幣。

因此,對手不斷嘗試操縱智能合約的執行以支持其活動。本質上,智能合約在分佈式和無權限網絡上運行,該網絡繼承了許多漏洞。在傳統的系統中,可以重新開發或修補這一小部分的中心化應用程序。

相反,在去中心化的區塊鏈網絡中,除非採取極端措施,否則無法在實時網絡中修改或升級已部署的智能合約。智能合約的一成不變特徵是其安全方面的優勢也是劣勢。由於這種不變性,黑客無法爲自己的利益進行更改或修改合約。

但是,部署後開發人員也無法修改智能合約應用程序。他們可以取消或終止合約並創建新的智能合約,然後再次部署它。因此,出於安全性考慮,在部署智能合約之前,應對智能合約進行大範圍的測試。我們重點介紹了以太坊智能合約架構的基本構建模塊,如圖1所示,其中包括以太坊的架構。

圖 1:  用於運行以太坊區塊鏈的環境是通過一個Web用戶界面與以太坊體系結構服務的四層進行交互,應用層,用於存儲區塊鏈數據的數據庫,用於支持共識協議的加密機制以及用於網絡層的Internet服務[20]。

a.應用層:以太坊客戶端在EVM中執行智能合約,其中智能合約與以太坊賬戶相關聯。以太坊支持兩種類型的賬戶:外部擁有賬戶(EOA)和合約賬戶。 EOA用於將用戶資金存放在Wei中,Wei是Ether的最小子面額,價值10-18 Ether。

EOA與公鑰相關聯並由公鑰解決;通過顯示相應私鑰的所有權來驗證對EOA的訪問。相反,合約帳戶與一段可執行的字節碼(即智能合約)相關聯,它定義了一些令人感興趣的業務邏輯。智能合約是DApp的基石。

DApp通常將用戶界面作爲其前端,並將一些智能合約作爲其後端。一些DApp會發行自己的稱爲令牌的加密貨幣,用於初始代幣發行(ICO)和交易所。基於以太坊的令牌是一種特殊的智能合約(例如ERC-20)[20]。

智能合約在EVM中執行,這些EVM是使用基於堆棧的體系結構的準圖靈完整機器。術語“quasi”是指執行受交易提供的gas限制。在以太坊應用層中,發生各種漏洞,導致許多攻擊,如應用層中的圖所示。

b.數據層:包含區塊鏈數據結構。交易是EOA(稱爲發件人)與另一個EOA或合約帳戶(稱爲收件人)之間的交互。交易由以下方式指定:

(i)nonce,它是用於跟蹤發送方已發起的交易總數的計數器;

(ii)收件人,該收件人指定了交易的目標EOA或合約帳戶;

(iii)價值,即從發件人向收款人轉移的金額(單位:Wei)(如果適用);

(iv)輸入,是與交易目的相對應的字節碼或數據;

(v)gasPrice和gasLimit,分別指定發送方願意向包含交易的區塊的獲勝礦工支付的單價和最大天然氣量;

(vi)(v,r,s),它是發送者的橢圓曲線數字簽名算法(ECDSA)簽名。執行交易會更新所涉及帳戶的狀態,從而更新區塊鏈。

c.共識層:確保區塊鏈的狀態一致。在撰寫本文時,以太坊大約需要12-14秒來創建一個區塊,這意味着多個礦工可以同時創建有效的區塊,並且可能有許多區塊。

以太坊使用GHOST共識協議的變體來選擇“最重”分支作爲主鏈,其中“heaviest”分支是根植於所討論的分叉的子樹,並且具有最高的累積區塊難度,同時注意到陳舊區塊不在主鏈上。但注意,以太坊用權益證明(PoS)替代其當前使用的工作量證明(PoW)。

d.網絡層:管理節點或客戶端的以太坊點對點(P2P)網絡,以使節點始終可以從某些活動節點獲取區塊鏈的更新狀態。

以太坊網絡是一個結構化的P2P網絡,其中每個節點(即客戶端)存儲整個區塊鏈的副本。爲了進行節點發現和路由,每個節點維護一個動態路由表,其中包含160個存儲桶,每個存儲桶最多包含16個其他節點的ID,IP地址,UDP / TCP端口條目。

以太坊使用RLPx協議發現目標客戶端,並使用以太坊有線協議來促進客戶端之間以太坊區塊鏈信息(例如交易,區塊)的交換。

e.以太坊區塊鏈環境:運行在如下四層的環境中:用戶與以太坊區塊鏈進行交互的Web界面;以太坊客戶的數據庫,用於存儲區塊鏈數據;出於安全目的的加密機制;以及支持以太坊節點之間的區塊鏈通信的互聯網基礎設施。

我們將以太坊區塊鏈架構與環境區分開來,因爲針對以太坊區塊鏈的攻擊可能來自環境,並且這些攻擊可能在環境中得到更好的解決,而不是由以太坊解決。


1.以太坊智能合約漏洞


重點介紹了以太坊體系每一層的智能合約漏洞,如圖2所示。

圖2:以太坊各層漏洞的分類

以太坊應用層:

重入性:此漏洞最初是從DAO攻擊中發現的[1],當外部被調用方合約在

用方合約完成之前(即某種意義上是循環調用)在調用方合約中回調函數時,會發生此漏洞。這使攻擊者可以繞開適當的有效性檢查,直到調用者合約被耗盡以太幣或交易用完爲止。

委託呼叫注入:首先從對Parity錢包的攻擊中發現了此漏洞[2]。爲了促使代碼重用,EVM提供了一個操作碼委託調用,用於將被調用方合約的字節碼插入到調用方合約的字節碼中。

結果惡意的被調用方合約可以直接修改(或操縱)調用方合約的狀態變量。此漏洞是由於被調用方合約可以更新調用方合約的狀態變量而導致的。聲明旨在通過委託調用作爲庫共享的無狀態合約,可完全防此漏洞。

凍結以太:首次從對Parity錢包的攻擊中發現了此漏洞[3]。該漏洞產生

由於用戶無法將錢存入其合約帳戶,而無法從這些帳戶中支出資金,從而有效凍結了他們的資金。

升級合約:引入合約升級的思想是爲了緩解智能合約一旦部署後就無法修改的問題,即使以後發現它們存在漏洞。爲了允許合約升級,有兩種方法:(i)將合約分爲代理合約和邏輯合約,以使開發人員可以升級後者而不是前者; (ii)使用註冊管理機構合約來保存更新後的合約。這些方法雖然有效,但卻引入了一個新的漏洞:當合約開發者變得惡意時,更新的合約可能是惡意的。此漏洞(即,不安全的聯繫人更新)仍然是一個未解決的問題。

具有意外還原的DoS:發生這種情況的原因是,由於主叫方合約遇到外部呼叫失敗而導致事務被還原,或者被叫方合約故意執行還原操作以中斷主叫方合約的執行。此漏洞是由執行被調用方合約還原的調用方合約引起的。通過使接收者調用交易來“提取”發件人爲接收者預留的資金,可以防止此漏洞,從而有效地防止了發件人的交易被還原。

整數上溢和下溢:首次從針對BEC令牌的攻擊中發現了此漏洞[4]。當運算的結果超出了Solidity數據類型的範圍時,就會發生這種情況,例如導致對攻擊者的餘額或其他狀態變量進行未經授權的操縱。該漏洞是由Solidity源代碼未在數字輸入上執行正確的驗證引起的,並且Solidity編譯器和EVM均未提供整數上溢/下溢檢測。可以通過使用SafeMath庫來防止此漏洞處理這些問題。

操縱餘額:當合約的控制流決策依賴於此值時,會發生此漏洞。平衡或解決(balance)平衡,攻擊者可以利用它使自己成爲唯一可以獲取金錢的人。可以通過不使用任何條件聲明中的合約餘額來防止此漏洞[5]。

通過tx.origin進行身份驗證:tx.origin是Solidity中的全局變量,它指的是發起有問題交易的原始EOA。當合約使用tx.origin進行授權時會發生此漏洞,這可能會受到網絡釣魚攻擊的危害。通過使用msg.sender而不是tx.origin進行身份驗證,可以防止此漏洞,因爲msg.sender返回導致該消息的帳戶。

錯誤的可見性:錯誤地指定功能的可見性,從而允許未經授權的訪問。

無保護的自殺:合約的所有者(或受委託的第三方)可以使用自殺或自毀方法銷燬合約。 取消合約時,將刪除其關聯的字節碼和存儲。 該漏洞是由合約強制執行的身份驗證不足引起的。 可以通過強制執行例如多因素身份驗證來緩解此漏洞,這意味着自殺操作必須得到多方的批准。

將以太幣泄漏到任意地址:當任意調用方都可以提取合約的資金時,該漏洞就不會發生,該調用方既不是合約的所有者,也不是向合約存入資金的投資者。

此漏洞是由調用者調用將以太幣發送到任意地址的功能時無法檢查呼叫者的身份引起的。 通過對發送資金的功能進行適當的身份驗證,可以防止此漏洞。

機密性失效:在區塊鏈中,由於區塊鏈的公共性質(即交易細節是衆所周知的),限制變量或函數的可見性並不能確保變量或函數是機密的。 防止此漏洞的一種可能解決方案是使用加密技術,例如定時承諾[6]。

簽名信息不足:當數字簽名對多個交易有效時,就會發生此漏洞,當一個發件人(例如Alice)通過代理合約向多個收件人匯款(而不是發起多個交易)時,可能會發生此漏洞。 此漏洞最初是在針對智能合約的重播攻擊中利用的。通過在每條消息中合併適當的信息(例如現時值和時間戳)可以防止此漏洞。

具有不受限制的操作的DoS:此漏洞首先從 Govern Mental 合約中觀察到[7]。

未經檢查的呼叫返回值:此漏洞也稱爲處理錯誤的異常。它有兩個變體,稱爲gas-less 發送和unchecked發送。當不檢查低級調用的返回值時會出現這種情況,即使函數調用拋出錯誤[8],執行也可能會繼續。

未初始化的存儲指針:回顧下,在Solidity中,合約狀態變量始終從插槽0開始連續放置在存儲中。對於複合局部變量(例如,struct,array或mapping),將引用分配給未佔用的對象存儲中的插槽以指向狀態變量。

錯誤的構造函數名稱:此漏洞最初是從Rubixi合約[9]中觀察到的,該構造函數的名稱不正確,它使任何人都可以成爲合約的所有者。在Solidity 0.4.22版之前,聲明與合約名稱相同的函數被視爲合約構造函數,該函數僅在創建合約時執行。

類型轉換:此漏洞最早在[10]中發現。以Solidity語言編寫的合約可以通過直接引用被調用方合約的實例來調用另一個合約。

過時的編譯器版本:當合約使用過時的編譯器時會發生,其中包含錯誤,因此使已編譯的合約易受攻擊。通過使用最新的編譯器可以防止此漏洞。

簡短地址:此漏洞最早在[11]中實現,並進行了廣泛討論。

以太幣丟失給孤立地址:以太幣失去到孤立發生在匯款時,以太坊僅檢查接收者地址的長度不超過160位,而不檢查接收者地址的有效性。 如果將錢發送到一個不存在的孤立地址,則以太坊會自動註冊該地址,而不是終止交易。

由於該地址未與任何EOA或合約帳戶相關聯,因此沒有人可以提取已轉移的資金,這實際上是丟失的。 此漏洞是由EVM不能孤立保護引起的。 在撰寫本文時,只能通過手動確保收件人地址的正確性來防止此漏洞。

調用堆棧深度限制:此漏洞是由EVM的執行模型不足引起的,並且已被EIP-150的硬分叉所消除,該硬叉重新定義了外部調用的耗油量規則,使其不可能達到1,024 in調用堆棧深度。

低估操作碼:首先從兩次DoS攻擊中發現了此漏洞[12] [13]。

交易順序依賴(又名前端運行):這是指併發性問題,即區塊鏈的即將到來的狀態取決於交易的執行順序,但是由礦工決定。

時間依賴關係:當合約在執行關鍵操作(例如匯款)時將block.timestamp用作觸發條件的一部分或作爲可由惡意礦工操縱的隨機性來源時,會發生此漏洞。該漏洞是由以太坊引起的,它只要求時間戳大於其母塊的時間戳並且在當前時鐘的900秒以內。

產生隨機性:例如,許多賭博和彩票合約都是隨機選擇中獎者,通常的做法是根據一些初始私有種子(例如block.number,block.timestamp,block。難易度或blockhash)生成僞隨機數。但是,這些種子由礦工完全控制,這意味着惡意礦工可以操縱這些變量使自己成爲贏家。此漏洞是由可操縱的entropy源引起的。


2.數據層漏洞


難以分辨的鏈:當以太坊分爲ETH和ETC兩條鏈[13]時,首先從跨鏈重放攻擊中觀察到此漏洞。回想一下,以太坊使用ECDSA簽署交易。在進行EIP-155 [7]硬分叉之前,每筆交易都包含六個字段(即,隨機數,收件人,值,輸入,gasPrice和gasLimit)。

但是,數字簽名不是特定於鏈的,因爲那時甚至還不知道特定於鏈的信息。結果,爲一個鏈創建的事務可被另一鏈重用。通過將chainID合併到字段中,已消除了此漏洞。

State Trie中的“空帳戶”:此漏洞首先從參考文獻[12] [13]中報告的DoS攻擊中發現的。


3.共識層的漏洞


可外包的難題:回想以太坊採用了名爲Ethash的PoW難題,該難題旨在抵禦ASIC,並能夠限制並行計算的使用(由於事實上,礦工的大部分工作將是讀取數據集。 通過有限的內存帶寬)。 但是,狡猾的礦工仍然可以將搜索難題解決方案的任務劃分爲多個較小的任務,然後將其外包。 該漏洞是由Ethash造成的,它僅使拼圖解決方案在原圖像搜索中部分順序,而不是依賴順序PoW。

概率最終性:此漏洞是由以太坊區塊鏈偏愛可用性而非一致性的設計引起的,這是根據CAP定理[14]選擇的。

帶有塊填充的DoS:首次從Fomo3D合約中觀察到此漏洞[15]。該漏洞僅導致攻擊者的交易包含在新開採的區塊中,而其他交易則被礦工放棄一段時間。當攻擊者提供更高的gasPrice以激勵礦工選擇攻擊者的交易時,可能會發生這種情況。此漏洞是由貪婪的採礦激勵機制引起的。在撰寫本文時,尚無解決方案來防止此漏洞。

誠實的採礦設想:此漏洞是由共識協議引起的,因爲它與激勵不兼容,請參見[16]。在撰寫本文時,此漏洞仍然是一個未解決的問題。

出塊獎勵:它是指出塊獎勵機制,用於應對由於快速生成塊而導致的陳舊區塊增加。但是,這種機制有一個副作用,即允許自私的礦工將陳舊的區塊變成出塊並獲得獎勵,從而有效地激勵了自私的採礦和雙重支出。

驗證者的困境:此漏洞最早在參考文獻[17]中報道,指的是當驗證新交易需要不費吹灰之力的計算時,無論礦工是否選擇驗證交易,都將受到攻擊。如果礦工驗證了計算量大的交易,那麼他們將花費大量時間,並在下一個區塊的競爭中爲攻擊者提供優勢;如果礦工未經驗證接受交易,則區塊鏈可能包含不正確的交易。此漏洞是由以太坊中驗證資源需求交易的高昂成本引起的。可以通過限制驗證塊中所有事務所需的計算量來緩解此漏洞[17]。但是,尚不清楚如何消除此漏洞。


4.網絡層的漏洞


無限節點的創建:此漏洞是針對Geth客戶端1.8之前的版本。在以太坊網絡中,每個節點都由唯一的ID標識,該ID是64字節的ECDSA公鑰。攻擊者可以在一臺計算機上創建無限數量的節點(即具有相同的IP地址),然後使用這些節點壟斷某些受害者節點的傳入和傳出連接,從而有效地將受害者與網絡中的其他對等節點隔離開來。

此漏洞是由對節點生成過程的弱限制引起的。通過使用IP地址和公鑰的組合作爲節點ID,可以消除此漏洞。格斯(Geth)開發人員尚未採用這種對策,他們認爲這對客戶端的可用性有負面影響。

不受限制的傳入連接:此漏洞在版本1.8 [18]之前的Geth客戶端中。 每個節點在任何時間點可以具有總數爲maxpeers的連接(默認值爲25),並且可以與其他節點發起多達1(1 + maxpeers)/2⌋個出站TCP連接。

但是,其他節點啓動的傳入TCP連接的數量沒有上限。 通過爲maxpeers建立與沒有出站連接的受害節點的許多傳入連接,攻擊者有機會使受害者黯然失色。 在Geth v1.8中,通過對到節點的傳入TCP連接的數量實施上限,默認值爲⌊maxpeers/3⌋= 8,消除了此漏洞。

公共對等體選擇:在Geth客戶端1.8之前的版本中檢測到此漏洞[18]。

對等體選擇:該漏洞指的是Geth客戶端在從其路由表中選擇節點以建立出站連接時,總是獲取隨機選擇的桶的頭部。由於每個存儲桶中的節點都是按活動排序的,因此攻擊者可以通過定期向Geth客戶端發送消息來使其節點始終位於其他節點之前。

通過在路由表中所有節點的集合中隨機選擇統一的節點,而不是僅從每個存儲桶的頭中隨機選擇節點,在Geth v1.9中已消除了此漏洞。

獨立塊同步:它允許攻擊者對以太坊P2P網絡進行分區,而不會壟斷受害者客戶端的連接。回想一下,每個塊標題都包含一個難度字段,該字段記錄了該塊的挖掘難度。區塊鏈的總難度用totalDifficulty表示,是直到當前區塊的難度之和。

RPC API暴露:此漏洞最初是通過對Geth和Parity客戶端的攻擊發現的[19]。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章