傅紫薇,沈子牛,陳云芳,張 偉
(南京郵電大學(xué) 計算機(jī)學(xué)院,江蘇 南京 210023)
區(qū)塊鏈技術(shù)依據(jù)去中心化、不可篡改和公開透明等特性[1],在近年受到了廣泛關(guān)注。區(qū)塊鏈2.0開始,智能合約與區(qū)塊鏈技術(shù)相結(jié)合,智能合約的引入使得各種去中性化應(yīng)用程序DApps迅速發(fā)展,極大地豐富了區(qū)塊鏈的應(yīng)用場景。但智能合約也帶來了一系列安全問題。以太坊作為目前最流行的智能合約平臺之一,已經(jīng)發(fā)生了多起重大安全事件,在這些安全事件中,絕大多數(shù)是由于智能合約被攻擊所致[2]。例如,2018年4月美鏈BEC的智能合約因其整數(shù)溢出漏洞而遭受攻擊[3],導(dǎo)致60億BEC代幣轉(zhuǎn)移到惡意賬戶,使得BEC市值幾乎歸零,給BEC市場交易帶來了嚴(yán)重的影響。2020年4月,黑客對DeFi交易平臺Lendf.Me[4]的智能合約實施了攻擊,損失金額達(dá)2500萬美元。
智能合約正處于發(fā)展階段,在設(shè)計、開發(fā)和應(yīng)用過程中常存在某些缺陷,且很多基于智能合約的去中心化應(yīng)用涉及資金流轉(zhuǎn),存在漏洞的合約更易成為攻擊者重點關(guān)注的目標(biāo),因而智能合約安全上鏈前的合約代碼安全審計和修復(fù)工作十分關(guān)鍵。到目前為止,已經(jīng)有大量的漏洞自動檢測方法或工具被研發(fā),他們重點關(guān)注某種或幾種漏洞類型,以設(shè)計專門的檢測方法發(fā)現(xiàn)這些漏洞,但在整個智能合約安全保障過程中這些還并不足夠。相比于傳統(tǒng)程序,智能合約在程序開發(fā)、編程語言和代碼優(yōu)化等方面的發(fā)展尚不完善,一些開發(fā)人員可能并不知道如何正確修改這些漏洞代碼,并且人工修復(fù)需要消耗大量資源。漏洞自動化修復(fù)技術(shù)可以實現(xiàn)漏洞代碼修復(fù)的自動化,能解決人工維護(hù)能力不足的問題,降低人工維護(hù)的成本,提高代碼質(zhì)量,因此加深對智能合約漏洞自動修復(fù)技術(shù)的研究很有必要。
該文提出了一個包含漏洞識別和補(bǔ)丁生成兩大關(guān)鍵步驟的智能合約部署前漏洞自動化修復(fù)流程,主要工作與貢獻(xiàn)如下:
(1)提出了一個適應(yīng)于自動化修復(fù)智能合約漏洞的框架,包括基于智能合約樣本和漏洞庫的輸入、漏洞檢測和報告生成、智能合約的修復(fù)以及修復(fù)后的驗證;
(2)基于框架的關(guān)鍵部分,分析了典型的智能合約漏洞產(chǎn)生原因和漏洞識別技術(shù),分類歸納了基于字節(jié)碼和源碼級別生成補(bǔ)丁的最新研究進(jìn)展;
(3)總結(jié)了修復(fù)后合約所需滿足的條件,并從有效性、成本問題、可擴(kuò)展性三個方面展開討論了補(bǔ)丁修復(fù)技術(shù)的性能評估需求。
智能合約是對現(xiàn)實中的合約條款執(zhí)行電子化的量化交易協(xié)議[5],區(qū)塊鏈技術(shù)的發(fā)展為其提供了可信的執(zhí)行環(huán)境。智能合約是傳統(tǒng)合約的數(shù)字化版本,簽署合約的參與者在內(nèi)容上達(dá)成一致,存在形式為一段可在區(qū)塊鏈上滿足執(zhí)行條件后自動執(zhí)行的代碼,它能實現(xiàn)區(qū)塊鏈中各類數(shù)據(jù)的控制和管理,可應(yīng)用于去中心化金融、醫(yī)療保健、供應(yīng)鏈和物聯(lián)網(wǎng)等多個方面。由于運(yùn)行于區(qū)塊鏈之上,智能合約遵循區(qū)塊鏈的種種機(jī)制,其程序特性與傳統(tǒng)應(yīng)用程序也有所差異。
區(qū)塊鏈?zhǔn)且环N分布式系統(tǒng),設(shè)計者引入激勵機(jī)制使得這類去中心化網(wǎng)絡(luò)可以達(dá)成共識,以保證網(wǎng)絡(luò)狀態(tài)的一致性。主流的共識算法有工作量證明PoW、權(quán)益證明PoS、授權(quán)股份證明DPoS等[6],通過共識算法可以決定哪個網(wǎng)絡(luò)節(jié)點擁有新區(qū)塊的記賬權(quán)。在以太坊中,網(wǎng)絡(luò)節(jié)點主要采用PoW共識算法來競爭記賬權(quán),需要打包的交易都位于交易池中,擁有記賬權(quán)的節(jié)點負(fù)責(zé)打包交易并記錄到新區(qū)塊。交易種類包括普通轉(zhuǎn)賬交易、創(chuàng)建合約交易和調(diào)用合約交易。智能合約的部署和調(diào)用,都通過交易的形式來實現(xiàn)。智能合約的執(zhí)行和交易合法性的驗證,都將占用一定的資源,因此擁有記賬權(quán)的節(jié)點可以收取一定的費(fèi)用作為獎勵,即Gas費(fèi)用。
智能合約每一條指令的執(zhí)行都對應(yīng)一定的Gas消耗,以太坊技術(shù)黃皮書[7]詳細(xì)講解了不同指令消耗的Gas數(shù)量,例如創(chuàng)建合約、數(shù)據(jù)存儲等操作比較昂貴,需消耗更多的Gas數(shù)量。用戶發(fā)起交易時需自行設(shè)定愿意支付的Gas用量上限并上交費(fèi)用,執(zhí)行合約代碼過程中交易實際產(chǎn)生的費(fèi)用等于實際消耗的Gas用量與單位Gas價格乘積所得的值,單位Gas的價格隨市場變化而變化。如果交易執(zhí)行完之后還有剩余Gas,將退還給交易發(fā)送方,而一旦執(zhí)行超過了Gas用量上限,交易將會失敗導(dǎo)致交易回滾,但在這個過程中已經(jīng)消耗的Gas用量并不會退還,Gas機(jī)制的設(shè)計除了起到獎勵礦工的作用,還在一定程度上防止了以太坊中一些惡意交易和資源浪費(fèi)現(xiàn)象的發(fā)生。
以太坊是最具代表性的智能合約應(yīng)用平臺,開發(fā)以太坊智能合約的編程語言主要是Solidity,除此之外還有Vyper、LLL等。編碼完成后的智能合約,由以太坊虛擬機(jī)(environment virtual machine,EVM)執(zhí)行編譯過程。EVM是一個基于堆棧的虛擬機(jī),為智能合約提供運(yùn)行環(huán)境,將智能合約源代碼編譯成可在以太坊上執(zhí)行的字節(jié)碼。字節(jié)碼由一串十六進(jìn)制的數(shù)字組成,以一個字節(jié)為單位,每個字節(jié)對應(yīng)一個操作碼(指令)或操作數(shù)。EVM字節(jié)碼指令集中目前大約有100多條指令,常見的有堆棧操作指令:PUSH、POP ,跳轉(zhuǎn)指令:JUMPI,數(shù)據(jù)讀寫操作指令:MLOAD、MSTORE、SLOAD、SSTORE,算數(shù)運(yùn)算操作指令:ADD、MUL、SUB等。
以太坊的賬戶分為合約賬戶和外部賬戶[8]。合約所有者充當(dāng)外部賬戶的角色向地址0X0處發(fā)起一個交易,交易中的data域中存放合約字節(jié)碼,并將交易的轉(zhuǎn)賬金額設(shè)為0,通過這種方式實現(xiàn)合約的創(chuàng)建。創(chuàng)建合約的交易利用區(qū)塊鏈中的共識機(jī)制實現(xiàn)部署,具體來說,區(qū)塊鏈P2P網(wǎng)絡(luò)中的全節(jié)點首先各自在本地執(zhí)行創(chuàng)建合約的交易,運(yùn)行合約代碼并修改數(shù)據(jù)和狀態(tài),經(jīng)共識算法決定出擁有記賬權(quán)的礦工后,礦工打包交易更新區(qū)塊,而后其他節(jié)點根據(jù)區(qū)塊中的交易再執(zhí)行一遍,更新本地的數(shù)據(jù)和狀態(tài)達(dá)到同步,完成部署過程。
最后,每個部署之后的合約會生成唯一的地址,形成合約賬戶。用戶使用外部賬戶向合約賬戶發(fā)起交易,同樣經(jīng)過區(qū)塊鏈共識的過程對交易進(jìn)行驗證并執(zhí)行,從而調(diào)用已經(jīng)被部署在鏈上的智能合約。部署之后的合約具有不可篡改、公開透明等特點。用戶可以通過運(yùn)行在windows、linux等操作系統(tǒng)上的以太坊客戶端實現(xiàn)合約調(diào)用的操作,EVM確認(rèn)觸發(fā)智能合約的條件滿足后,解釋執(zhí)行合約代碼。
智能合約作為圖靈完備的程序腳本,與傳統(tǒng)應(yīng)用程序有多個方面的區(qū)別,表1展示了智能合約應(yīng)用與傳統(tǒng)軟件應(yīng)用在不同角度的對比分析。
表1 智能合約應(yīng)用與傳統(tǒng)軟件應(yīng)用對比分析
基于以上的比較,從學(xué)習(xí)成本、開發(fā)難度等方面來看,由于智能合約發(fā)展歷史較短,各種開發(fā)指導(dǎo)文檔以及測試框架都比較匱乏,Solidity作為一種較新的編程語言,自身也存在很多局限性,而且缺少功能強(qiáng)大的調(diào)試器,這些因素導(dǎo)致智能合約開發(fā)人員的學(xué)習(xí)成本和開發(fā)難度更高;從安全需求方面來看,傳統(tǒng)應(yīng)用程序的編碼通常對用戶不可見,只在用戶層提供一些接口,而智能合約的公開可見性,增加了受攻擊的風(fēng)險,又由于涉及大量資金交易,智能合約對安全性的要求比傳統(tǒng)應(yīng)用程序更嚴(yán)格;另外,從代碼優(yōu)化和漏洞修復(fù)方面來看,傳統(tǒng)軟件應(yīng)用往往注重于功能擴(kuò)展和安全性能的優(yōu)化,而智能合約遵循Gas機(jī)制,使得合約代碼在優(yōu)化和漏洞修復(fù)過程還需著重考慮成本問題。Gas機(jī)制是智能合約性能優(yōu)化過程中,區(qū)別于傳統(tǒng)軟件應(yīng)用的一個顯著特征。
智能合約與傳統(tǒng)應(yīng)用程序存在的種種差異為智能合約的安全問題及其漏洞自動修復(fù)技術(shù)帶來了不一樣的挑戰(zhàn)。當(dāng)前針對智能合約漏洞檢測的研究較多,而修復(fù)技術(shù)的研究相對較少,也缺乏整體認(rèn)識。對于智能合約上鏈前的代碼漏洞修復(fù),認(rèn)為其同傳統(tǒng)軟件修復(fù)技術(shù)[10-11]具有一些共性,同樣存在漏洞定位、補(bǔ)丁生成和補(bǔ)丁驗證等步驟,基于此,可以建立專注于智能合約的自動化修復(fù)方案。該文總結(jié)性地提出了適應(yīng)于智能合約漏洞自動化修復(fù)技術(shù)的研究框架,符合目前已有的智能合約漏洞自動化修復(fù)的一般流程,如圖1所示。
圖1 智能合約漏洞自動化修復(fù)框架
首先,將待測合約Solidity源碼或者編譯之后的字節(jié)碼作為輸入,利用智能合約漏洞庫中相關(guān)漏洞類型和特征的記錄,對合約代碼進(jìn)行漏洞分析,再采用漏洞檢測技術(shù)識別漏洞,判斷是否存在安全漏洞并生成漏洞檢測結(jié)果報告。報告可以是json格式的文件,其中包含漏洞的類型和所在位置等重要說明。
特征提取與識別是自動修復(fù)過程的前提,其識別與定位的準(zhǔn)確性會對后面的修復(fù)工作產(chǎn)生直接的影響,近年來得到了研究人員的廣泛專注。主要可采取模糊測試、符號執(zhí)行、污點分析以及形式化驗證等不同的方法手段[12]對程序進(jìn)行分析,或者嵌入現(xiàn)有的多種漏洞自動檢測工具形成docker鏡像提供漏洞檢測的功能,為后續(xù)進(jìn)行補(bǔ)丁修復(fù)提供有效信息。
補(bǔ)丁修復(fù)與驗證是消除漏洞的關(guān)鍵步驟,依據(jù)漏洞報告產(chǎn)生的漏洞分析與定位描述,將通過自動修復(fù)方案產(chǎn)生一系列補(bǔ)丁修復(fù)語句或根據(jù)預(yù)先定義的修復(fù)模板,生成候選補(bǔ)丁。然后在漏洞位置依據(jù)候選補(bǔ)丁進(jìn)行增加、刪除和替換語句的操作,再通過軟件測試方法使用測試集測試或者使用漏洞測試工具對修復(fù)代碼的正確性進(jìn)行檢驗。目前已有的自動修復(fù)技術(shù)可根據(jù)修復(fù)語言級別分為基于字節(jié)碼修復(fù)與基于源碼修復(fù),具體修復(fù)方案的性能可依據(jù)漏洞修復(fù)的有效性、Gas成本消耗、修復(fù)技術(shù)可擴(kuò)展性等角度進(jìn)行評估。
已修復(fù)合約和修復(fù)報告是通過漏洞修復(fù)技術(shù)生成的結(jié)果輸出。修復(fù)報告包含已修復(fù)漏洞類型的說明,并記載修復(fù)所在位置、具體操作、時間消耗等詳細(xì)信息,可供安全人員或開發(fā)人員查閱,有效減少合約開發(fā)過程產(chǎn)生的潛在漏洞,提高安全性。
針對智能合約漏洞自動化修復(fù)流程所依賴的關(guān)鍵部分,下面將展開分析與闡述智能合約漏洞特征識別和補(bǔ)丁生成相關(guān)的技術(shù)手段。
識別智能合約漏洞需要提取代碼特征并分析特征,因此需要大量詳細(xì)的漏洞信息數(shù)據(jù)的支持,表2展示了現(xiàn)有的記錄智能合約漏洞信息的資源庫。漏洞資源庫對智能合約開發(fā)過程中常見的安全漏洞類型及其代碼實例做了描述,可為開發(fā)人員提供指導(dǎo)信息,也為安全審計的漏洞自動修復(fù)過程提供漏洞特征信息。
以太坊智能合約的安全漏洞種類眾多,根據(jù)漏洞發(fā)生的層次,可以分為高級語言、虛擬機(jī)和區(qū)塊鏈三個層面[13]。高級語言層面引入的安全漏洞主要與編程語言設(shè)計、用戶程序的編寫等存在缺陷有關(guān),如整數(shù)溢出、未檢查外部調(diào)用返回值等,虛擬機(jī)層面的安全漏洞則與EVM的實現(xiàn)及其字節(jié)碼規(guī)范有關(guān),如重入漏洞,而區(qū)塊鏈層面的安全漏洞則主要與區(qū)塊鏈本身的特性相關(guān),如偽隨機(jī)數(shù)漏洞。下面主要介紹6種典型智能合約漏洞類型的產(chǎn)生原因以及相應(yīng)的修復(fù)策略。
表2 智能合約漏洞信息庫
(1)重入漏洞。
智能合約在執(zhí)行外部調(diào)用的交互過程中,某個合約調(diào)用另一個合約但被再次進(jìn)入,或形成遞歸調(diào)用導(dǎo)致將此合約賬戶的資源消耗完的過程,稱為重入攻擊[14]。重入攻擊是智能合約中典型的攻擊手段之一。它攻擊成功的原因是合約中的代碼缺陷,即狀態(tài)變量的賦值操作在調(diào)用外部函數(shù)的語句之后發(fā)生。修復(fù)重入攻擊可以使用互斥鎖,保證事務(wù)執(zhí)行的原子性,防止重新進(jìn)入函數(shù),或者將合約中的狀態(tài)變量賦值操作移動到在外部調(diào)用之前來避免漏洞發(fā)生。
(2)整數(shù)溢出。
一個整數(shù)變量在以太坊虛擬機(jī)中會被指定為固定大小的數(shù)據(jù)類型,因此只能存儲一定范圍內(nèi)的數(shù)字,例如uint8類型的整數(shù)變量只能存儲0到255之間的數(shù)字,值為255時,如果加1將導(dǎo)致每一位數(shù)發(fā)生翻轉(zhuǎn)從而產(chǎn)生整數(shù)上溢,同理值為0時,減1會導(dǎo)致整數(shù)下溢。整數(shù)溢出漏洞也常出現(xiàn)在其他的編程語言當(dāng)中。針對整數(shù)溢出的修復(fù),可以通過使用OpenZeppelin維護(hù)的SafeMath庫來處理算術(shù)邏輯[15],它封裝了算數(shù)運(yùn)算接口,可以避免產(chǎn)生溢出漏洞。
(3)權(quán)限控制。
權(quán)限控制問題主要是合約中函數(shù)或變量的越權(quán)訪問,例如智能合約的Solidity編程語言與其他高級語言類似,也有public、private等函數(shù)屬性,這些屬性控制著訪問函數(shù)的方式[16]。沒有被正確設(shè)置訪問權(quán)限的函數(shù),會增加它們被非法調(diào)用的風(fēng)險。預(yù)防和修復(fù)這類漏洞,需要在代碼編寫過程中充分檢查并設(shè)置嚴(yán)謹(jǐn)?shù)暮瘮?shù)訪問權(quán)限,某些有訪問控制要求的變量可以使用函數(shù)修飾符modifier進(jìn)行修飾。
(4)偽隨機(jī)數(shù)。
由于區(qū)塊鏈分布式共識的特征,以太坊的智能合約無法支持真正的隨機(jī)數(shù)。很多區(qū)塊鏈上的開獎類游戲采用隨機(jī)數(shù)邏輯作為開獎依據(jù),利用區(qū)塊打包時間、區(qū)塊打包難度等信息作為計算隨機(jī)數(shù)的種子,這種方式產(chǎn)生的數(shù)是偽隨機(jī)數(shù),有可能被預(yù)測到。針對隨機(jī)數(shù)攻擊的修復(fù)建議可以是使用鏈下方式生成隨機(jī)數(shù),然后利用預(yù)言機(jī)oracle傳遞到鏈上供使用[17]。第二種方式,可以使用當(dāng)前區(qū)塊的哈希值作為隨機(jī)數(shù)種子[18],由于當(dāng)前區(qū)塊在打包之前是不可被預(yù)測的,用戶提出交易請求后,合約記錄執(zhí)行此交易所在區(qū)塊的區(qū)塊哈希值,此值無法被預(yù)測,可以促使產(chǎn)生隨機(jī)結(jié)果。
(5)Tx.origin漏洞。
Tx.origin是智能合約中的一個全局變量,返回最初調(diào)用合約的賬戶地址。如果受害合約內(nèi)通過此變量對調(diào)用合約者的身份進(jìn)行驗證[19],容易產(chǎn)生Tx.origin漏洞。某些惡意的中間合約可能會利用Tx.origin變量等于最初調(diào)用受害合約的賬戶地址這一特征,實現(xiàn)越權(quán)操作。為避免這類攻擊事件的發(fā)生,在一些權(quán)限驗證的過程中盡量不要使用Tx.origin,而改用msg.sender,msg.sender返回的是當(dāng)前調(diào)用合約的賬戶地址,可以阻止中間合約通過身份驗證。
(6)未檢查call返回值。
Solidity中的一些底層調(diào)用函數(shù),如call()、callcode()、delegatcall()和send(),在執(zhí)行結(jié)束之后僅返回布爾值true或false來表示是否執(zhí)行正確,執(zhí)行過程中若發(fā)生錯誤并不會拋出異常,而會直接繼續(xù)執(zhí)行后面的代碼。所以如果對這類函數(shù)不進(jìn)行返回值的檢查,將有可能致使意外發(fā)生[20]。處理這類漏洞最好是在調(diào)用這些函數(shù)時檢查其返回值,并對可能發(fā)生的異常預(yù)先設(shè)置解決方案。
近年來學(xué)術(shù)界對智能合約漏洞檢測進(jìn)行了廣泛和深入的研究[21-22],主要方法包含模糊測試、污點分析、符號執(zhí)行、形式化驗證等。
模糊測試是向程序提供大量非預(yù)期的輸入,在運(yùn)行時監(jiān)測異常以發(fā)現(xiàn)漏洞的方法。對智能合約進(jìn)行漏洞檢測時,模糊測試通過迭代生成隨機(jī)并且不同的交易,探索合約是否存在異常的執(zhí)行狀態(tài)。ReGuard[23]是一種專用于檢測可重入漏洞的模糊分析器,其利用模糊器不斷生成隨機(jī)輸入,執(zhí)行運(yùn)行時跟蹤然后傳遞給檢測器檢測漏洞是否存在。Contractfuzzer[24]也是一款基于模糊測試的漏洞檢測框架,但擴(kuò)展了檢測的范圍,可檢測包括重入漏洞、時間戳依賴等7種漏洞。
污點分析將輸入數(shù)據(jù)標(biāo)記為污點作為源,在智能合約運(yùn)行過程中進(jìn)行傳播,追蹤污點傳播路徑并判斷數(shù)據(jù)的流向,從而發(fā)現(xiàn)可疑的數(shù)據(jù)操作來識別漏洞。Sereum工具[14]利用污點跟蹤技術(shù)監(jiān)控智能合約執(zhí)行過程中的數(shù)據(jù)流,自動檢測異常狀態(tài),實現(xiàn)了對3種不同的重入攻擊模式的檢測。已有的一些漏洞檢測方案通常將其與符號執(zhí)行技術(shù)融合,例如Osiris[25]為檢測智能合約整數(shù)溢出,首先通過符號分析確定程序路徑分支,將路徑中的執(zhí)行指令傳遞給污點分析器,然后利用污點分析器在堆棧(Stack)、內(nèi)存(Memory)、存儲(Storage)等位置引入污點并傳播污點,最后通過檢查已執(zhí)行的指令中數(shù)據(jù)是否被整數(shù)溢出錯誤污染。
符號執(zhí)行是一種程序分析方法,對智能合約進(jìn)行分析時,使用符號值代替合約中的變量值,不斷解析指令形成可執(zhí)行路徑,然后利用約束求解器求解滿足約束的輸入,檢測輸入的符號值是否存在異常問題。這種方法無需模擬以太坊上的執(zhí)行環(huán)境動態(tài)地進(jìn)行檢測,減少了不確定性,有良好的代碼覆蓋率,已經(jīng)有多種基于符號執(zhí)行開發(fā)的針對智能合約漏洞的靜態(tài)分析工具[26-27]。
形式化驗證的方法是利用形式化語言對智能合約進(jìn)行建模,構(gòu)建推理系統(tǒng)來驗證合約代碼的正確性,文獻(xiàn)[28]中總結(jié)了形式化驗證在智能合約方面的研究,并將已有的基于形式化驗證智能合約的方法分為8類進(jìn)行闡述,分別是基于定理證明的形式化方法、基于符號執(zhí)行的形式化方法、基于模型檢測的形式化方法、基于規(guī)約語言的形式化方法、基于形式化建模的形式化方法、基于有限狀態(tài)機(jī)的形式化方法、基于著色 Petri 網(wǎng)的形式化方法、基于運(yùn)行時驗證的形式化方法。
除了這幾種主流方法,近年來機(jī)器學(xué)習(xí)的進(jìn)步已經(jīng)充分體現(xiàn)了其技術(shù)優(yōu)勢,研究人員也積極嘗試結(jié)合機(jī)器學(xué)習(xí)算法[29-30],對智能合約代碼進(jìn)行特征提取,建立檢測模型來識別易受攻擊的智能合約,并得到了良好的性能。
目前對智能合約進(jìn)行補(bǔ)丁修復(fù)的技術(shù)主要采用了基于模板、基于遺傳搜索等,表3列出了已有的智能合約漏洞自動化修復(fù)工具。而從補(bǔ)丁修復(fù)的語言層面來看,可分為基于源代碼和基于字節(jié)碼的修復(fù)。源碼級別的修復(fù)對使用者來說具有更高的可讀性,字節(jié)碼的修復(fù)可獨(dú)立于源碼語言,避免版本原因造成不正確修復(fù)等問題。下面將分別對這兩類補(bǔ)丁修復(fù)工具所涉及的技術(shù)進(jìn)行梳理和介紹。
表3 智能合約漏洞自動化補(bǔ)丁修復(fù)工具
(1)基于源碼。
智能合約源碼級別的漏洞修復(fù)直接對產(chǎn)生漏洞處的Solidity源碼進(jìn)行程序分析,然后采用不同的修復(fù)技術(shù)產(chǎn)生Solidity源碼補(bǔ)丁進(jìn)行自動修復(fù)。例如圖2(a)中代碼有典型的重入缺陷,結(jié)合漏洞類型及其產(chǎn)生的原因,sGUARD工具應(yīng)用預(yù)定義的修復(fù)模板,給withdraw()取款函數(shù)添加一個nonReentrant_修飾器,應(yīng)用了此修飾器的withdraw()函數(shù)會首先執(zhí)行圖2(b)中第2~3行的語句,為函數(shù)中提取資金的進(jìn)程上鎖,實現(xiàn)事務(wù)原子性,修復(fù)缺陷。此外sGUARD還構(gòu)建了修復(fù)整數(shù)溢出和Tx.origin漏洞的補(bǔ)丁模板?;谀0宓男迯?fù)技術(shù)由于較高的針對性,其修復(fù)質(zhì)量比較高,但其局限性在于只能用于修復(fù)特定的場景和有限的漏洞種類。
Yu等人[35]采用多任務(wù)遺傳算法實現(xiàn)了自動修復(fù)工具SCRepair,他們提出的搜索技術(shù)使用移動、插入、替換三種變異算子將大量小的語句變化植入漏洞合約,通過了所有測試集實例的補(bǔ)丁成為合約代碼的候選補(bǔ)丁。最終實現(xiàn)了異常處理漏洞、整數(shù)溢出、交易順序依賴、重入等問題的修復(fù)。為提升搜索效率,SCRepair將搜索空間分割為較小的互斥搜索空間,并使用并行搜索,同時通過公式計算候選補(bǔ)丁的Gas消耗篩選高質(zhì)量補(bǔ)丁。這類方法的搜索深度往往有限,產(chǎn)生的補(bǔ)丁質(zhì)量和修復(fù)速度也有待提升。
(a)重入漏洞代碼
(2)基于字節(jié)碼。
智能合約編譯之后形成字節(jié)碼,基于字節(jié)碼的修復(fù)往往先使用靜態(tài)分析技術(shù)分析程序的控制依賴關(guān)系、數(shù)據(jù)依賴關(guān)系,然后獲得字節(jié)碼級別的語義信息以識別不正確的數(shù)據(jù)流或控制流[31],這個過程也可以直接使用當(dāng)前已有的靜態(tài)漏洞檢測工具來實現(xiàn)。收集到錯誤的信息流之后,利用字節(jié)碼重定位技術(shù),將字節(jié)碼補(bǔ)丁應(yīng)用到相應(yīng)位置,從而實現(xiàn)修復(fù)。
由于智能合約的運(yùn)行環(huán)境EVM是基于堆棧的體系結(jié)構(gòu),程序跳轉(zhuǎn)指令JUMPI的目的地址(如0x000a)都會通過PUSH指令存放在堆棧中?;谧止?jié)碼的修復(fù)在代碼地址空間中插入任何語句時,原先的空間布局都可能會改變,因此必須更新所有相關(guān)的地址引用,以確保修改后的程序能調(diào)用正確的地址引用,調(diào)整地址引用的過程稱為字節(jié)碼重定位。字節(jié)碼重定位是基于字節(jié)碼修復(fù)的技術(shù)重點同時也是技術(shù)難點。
為了解決這一挑戰(zhàn),Rodler等人[32]實現(xiàn)的自動修復(fù)工具EVMpatch在利用靜態(tài)分析技術(shù)得到程序的控制流圖之后,將需要修復(fù)的指令所在的基本塊復(fù)制到代碼地址空間的末尾空閑處,然后對此基本塊使用預(yù)定義的字節(jié)碼補(bǔ)丁模板進(jìn)行修正,再用JUMPI指令重定向到此基本塊,替換原始的基本塊。這樣就避免了初始的代碼地址空間被修改。但這種基本塊級別的重定位方式,在末尾處占據(jù)了與原始基本塊相同大小的地址空間,增加了整體的代碼量。
針對EVMpatch在字節(jié)碼重定位方面存在的不足,F(xiàn)erreira等人[33]采用在預(yù)定義的模板中添加語義信息創(chuàng)建修復(fù)補(bǔ)丁,并在代碼漏洞之處做出直接修改的方式來修復(fù)漏洞。他們在修改之前先創(chuàng)建一個地址副本,用于記錄原始合約所有指令的地址。掃描程序控制流圖進(jìn)行修復(fù)工作,如圖3中,插入虛線框內(nèi)的修復(fù)語句之后,會更新地址副本中所有修復(fù)語句之后的所有地址指令。最后對于跳轉(zhuǎn)地址的更新,分兩步進(jìn)行:第一步,找到修復(fù)后的地址空間中,所有不同于原始地址的JUMPDEST指令,記載它當(dāng)前所在的地址,如圖3中的JUMPDEST地址由0x00c3變?yōu)?x00d2;第二步,查找PUSH值等于原始JUMPDEST指令地址的PUSH指令,使用地址副本中記錄的新值替換PUSH值,如圖3中等于原始JUMPDEST指令地址0x00c3的PUSH值應(yīng)當(dāng)替換為0x00d2。這種字節(jié)碼重定位的方式無需占用多余的地址空間,節(jié)省了一定的資源。
考慮智能合約與傳統(tǒng)應(yīng)用程序的差異,驗證智能合約補(bǔ)丁修復(fù)方案性能評估指標(biāo)所涉及的內(nèi)容也有所不同,修復(fù)后的合約應(yīng)該滿足以下3個先決條件:
(1)通過所有測試集中的測試用例,不存在漏洞報告中的漏洞;
(2)合約如需部署上鏈,執(zhí)行消耗的Gas不超過其Gas用量上限;
(3)不影響原始合約的正常功能。
通過分析上述條件,從有效性、Gas消耗、可擴(kuò)展性三個方面討論智能合約補(bǔ)丁修復(fù)的性能評估需求。
(1)有效性。
修改后的智能合約程序要求通過所有測試實例,且合約的正常功能不被破壞,保持與原始合約一致,才被認(rèn)定是有效的修復(fù)。因此,有效性包含正確性和功能一致性兩方面。為了驗證智能合約修復(fù)的正確性,可利用軟件測試方法,使其通過測試用例集進(jìn)行驗證,但這種方法的覆蓋率有限,另外還可以利用現(xiàn)有的漏洞檢測工具如slither[36]對修復(fù)合約進(jìn)行漏洞測試,判斷漏洞是否已被修復(fù),這種方式的驗證效果依賴于檢測工具本身的準(zhǔn)確性。為了驗證功能一致性,可重現(xiàn)合約歷史交易。即通過區(qū)塊鏈瀏覽器如etherscan查詢大量的原始合約正常歷史交易記錄,分別對修復(fù)合約與原始合約模擬重現(xiàn)這些交易,判定兩者的功能是否一致。
(2)Gas消耗。
運(yùn)行于區(qū)塊鏈系統(tǒng)上的智能合約,計算資源受到限制,Gas消耗問題需要著重考慮。代碼修復(fù)會改變代碼本身的大小,增加的計算會增加額外的Gas消耗,也因此在求解補(bǔ)丁修復(fù)語句時,在保證正確修復(fù)漏洞的情況下,應(yīng)當(dāng)追求更少的代碼改動和Gas消耗。一些智能合約漏洞補(bǔ)丁修復(fù)工具(如sGUARD、SMARTSHIELD等)通過重現(xiàn)合約交易的方式,比較修復(fù)合約與原始合約的Gas及時間消耗上的差異,來衡量他們的平均修復(fù)成本以及修復(fù)質(zhì)量。為了優(yōu)化補(bǔ)丁的質(zhì)量,SCRepair綜合考慮會影響成本的參數(shù),將智能合約的Gas消耗量化為一個計算公式,在產(chǎn)生大量候選的修復(fù)補(bǔ)丁時,通過公式計算Gas消耗并排序,擇優(yōu)進(jìn)行修復(fù)。
(3)可擴(kuò)展性。
應(yīng)用程序的功能需求可能會面臨更新,應(yīng)用程序的擴(kuò)展性表現(xiàn)為功能模塊之間的依賴與耦合程度。擁有良好擴(kuò)展性的應(yīng)用程序意味著可以更好地支持功能修改和拓展。對于智能合約漏洞的自動化補(bǔ)丁修復(fù)工具而言,如果實現(xiàn)模塊化的可修復(fù)漏洞種類增加、檢測功能與補(bǔ)丁修復(fù)功能分離,將可以提高其擴(kuò)展性。ELYSIUM、EVMpatch等工具均直接利用了現(xiàn)有的漏洞檢測工具在補(bǔ)丁修復(fù)前定位合約的漏洞,并在補(bǔ)丁修復(fù)后驗證修復(fù)效果。
如前所述,已有部分研究人員在智能合約自動化修復(fù)問題方面做出了貢獻(xiàn),并取得了一定的成果。但與傳統(tǒng)程序自動修復(fù)技術(shù)相對比,智能合約自動修復(fù)技術(shù)研究時間較短,仍有許多問題尚未得到解決,筆者認(rèn)為未來在如下幾個方面值得關(guān)注:
(1)在漏洞識別階段,基于動態(tài)的運(yùn)行測試方法,其檢測準(zhǔn)確率依賴于測試用例,不能保證代碼覆蓋率,提高動態(tài)檢測方法的準(zhǔn)確率需要有良好的測試用例集。而基于靜態(tài)的分析方法可能無法檢測一些運(yùn)行時的異常行為,因而存在一定的誤報率。漏洞識別的準(zhǔn)確性將直接關(guān)系到后續(xù)補(bǔ)丁修復(fù)工作,如何將幾種主流的方法相結(jié)合,融合各自的優(yōu)勢以期找到更具適應(yīng)性和更高準(zhǔn)確率的智能合約漏洞檢測方案,是進(jìn)一步研究的方向。
(2)目前已實現(xiàn)的補(bǔ)丁生成方案采用的技術(shù)方法比較單一,主要是基于模板或結(jié)合語義的方法。原因是前期程序分析階段過程中,利用代碼覆蓋率高的靜態(tài)分析技術(shù)可以方便地獲取程序語義信息,另外基于模板的補(bǔ)丁修復(fù)可以利用漏洞特征預(yù)先定義修復(fù)模式,修復(fù)效率較高。但基于模板修復(fù)的方式,其修復(fù)能力和范圍受限于預(yù)先定義的模板數(shù)量和質(zhì)量,可修復(fù)漏洞的種類有限,難以廣泛應(yīng)用,如何結(jié)合人工智能技術(shù)和智能合約應(yīng)用場景語義以探索具有場景語義的修復(fù)模板值得探討。傳統(tǒng)軟件缺陷自動修復(fù)方面,已有基于搜索[37]、基于語義[38]、基于模板[39]以及基于統(tǒng)計分析[40]等多種方法,在未來的方案探索中,可進(jìn)一步結(jié)合這些方法建立適用于智能合約部署前的自動化修復(fù)技術(shù),填補(bǔ)當(dāng)前的研究空缺。
(3)在漏洞補(bǔ)丁修復(fù)能力方面,已有的幾種補(bǔ)丁修復(fù)工具僅能修復(fù)2~7種漏洞,且這些工具關(guān)注更多的是高級語言或虛擬機(jī)層面的漏洞,而與區(qū)塊鏈本身特性有關(guān)的漏洞諸如時間戳依賴、條件競爭等很少被研究。隨著智能合約應(yīng)用規(guī)模的發(fā)展,研究智能合約更深層次漏洞的自動修復(fù)技術(shù)顯得尤為重要,研究者需要加強(qiáng)對不同層面漏洞的關(guān)注,并不斷擴(kuò)大可修復(fù)的漏洞類型。另外當(dāng)前的一些自動化修復(fù)工具誤報率仍然較高,修復(fù)過程產(chǎn)生的額外成本也是一直有待改進(jìn)的問題。
(4)智能合約上鏈之前的漏洞自動修復(fù)不是一個一蹴而就的工作,智能合約漏洞問題也不會因此完全消失,存有漏洞的合約部署上鏈之后暴露在公眾視野種將會存在更大的風(fēng)險,鏈上合約安全問題同樣值得關(guān)注。智能合約升級作為一種修復(fù)驗證過程中遺漏錯誤的補(bǔ)救方案,可以根據(jù)地址重定向替換原先存在于鏈上的漏洞合約[41]。另外,一些研究提出了通過監(jiān)測鏈上交易執(zhí)行,及時阻止危險交易發(fā)生的方案來提高安全性[42]。合約升級和交易保護(hù)措施為解決鏈上合約安全提供了新的思路。
基于區(qū)塊鏈技術(shù)的智能合約上鏈之后難以修改,安全性需求高。該文以典型的以太坊平臺為例,介紹了智能合約的運(yùn)行過程和開發(fā)特性,探討了其上鏈前安全審計過程中的漏洞自動修復(fù)技術(shù),指出了當(dāng)前技術(shù)方案在漏洞修復(fù)準(zhǔn)確率、修復(fù)代價、修復(fù)覆蓋度等方面的不足,并提出了未來進(jìn)一步研究的方向。