區塊鏈 Blockchain Ethereum 比特幣 加密貨幣 智慧合約 去中心化 資訊安全

雙重支付/51%攻擊/女巫攻擊堪慮 Solidity語法漏洞須防

程式碼到應用均可攻擊 區塊鏈智慧合約仍多風險

區塊鏈的狂潮已席捲全世界,不論是比特幣交易系統,還是包含智慧合約系統的以太幣,都是不容忽視的一種新興交易與記帳技術。本文將介紹區塊鏈和智慧合約,並進一步說明數種攻擊方法,顯示區塊鏈技術可能不如想像中來得安全。

 

區塊鏈起源於比特幣概念(先有比特幣的概念才有區塊鏈)。作為分散式記帳系統的核心技術,區塊鏈已被認為在金融、物聯網、商業貿易、資產管理等眾多領域都擁有廣泛的應用前景。區塊鏈依靠複雜的密碼學來加密資料,再透過分散式演算法,讓最讓人擔憂的交易雙方信任問題,可以在不需要第三方介入的前提下讓使用者達成交易,也因少了第三方的關係,使得交易速度可以更快、交易成本能夠更低,隨著近年來的硬體技術進步,引爆風潮。區塊鏈具備以下幾個特點:

1. 去中心化:正如前述,區塊鏈不需要中立的監察機關。

2. 不可竄改:資料一旦寫入區塊鏈,便難以更改;若是因合約所建立者,完全無法變更。

3. 交易公開透明:任何人的手上都可以持有帳本,且所有的區塊建立和交易都是可以被認證的。

4. 加密:任何的交易都是使用公私鑰進行加密的,交易的各終點也是錢包位址而非銀行帳戶。

然而,不少人以為區塊鏈是基於密碼學的安全基礎所建立的去中心化、不可篡改技術就能絕對安全,完全不用害怕惡意的攻擊者。但事實上,區塊鏈從程式碼到應用端,包括智慧合約、錢包、交易所等都可能成為惡意攻擊者的目標。

相關背景知識介紹

為了能更加深入了解區塊鏈相關技術,先就加密貨幣、區塊鏈的架構與智慧合約做一介紹。

加密貨幣

加密貨幣是一種使用密碼學原理來確保交易安全及控制交易單位創造的交易媒介,簡單來說,就是一種建立在以密碼學為安全前提的貨幣。最早的加密貨幣即為家喻戶曉的比特幣,來自一篇署名中本聰(Satoshi Nakamoto)的《Bitcoin: A Peer-to-Peer Electronic Cash System》論文,透過解決數學難題來獲得比特幣(俗稱挖礦),並結合區塊鏈的技術,讓加密貨幣得以線上交易,由此建構出一個無須中央機構管理的貨幣系統。其加密貨幣的交易,主要是透過兩個線上錢包(Wallet),藉由公私鑰進行點對點的交易,而上述的過程也會被寫進區塊內,在區塊內代表兩個交易方使用的是兩個錢包位址,並非實際的雙方資料。

而隨著比特幣的興起,許多的加密貨幣也隨之誕生,像是最早建立起智慧合約的以太幣(Ether)也隨著這股熱潮出現,其因應以太幣所建立之區塊鏈的平台以太坊(Ethereum),讓使用者能夠建立屬於他們自己的區塊鏈應用,也可以自行建立與他人的交易方式。

對於一般銀行帳戶,攻擊者能夠「駭」進中央控管的機制進行偷竊,但對於加密貨幣並沒辦法藉由上述的方法進行偷竊。因為加密貨幣並不存在一個中央控管的機構,即便是駭進交易所網站,若未能取得該交易所保管的交易人私鑰,也無法竊取加密貨幣。

區塊鏈的架構

區塊鏈的構造大致可以分為區塊(Block)、雜湊值(Hash Value,即Digest)、時間戳記(Timestamp)、非對稱加密、流水號(Nonce)。當然區塊鏈的構造可以更為複雜,更可以分成不同功能的層級,區塊鏈結構如圖1所示。

圖1  區塊鏈的基本架構。

‧區塊編號:區塊的編號,往前遞增。

‧Nonce:Nonce值為一隨機值,系統藉由這個Nonce值讓這個區塊的Block Header Hash值小於一個被設定好的難度目標值(Difficulty Target),為了要解出Nonce的計算過程稱為「挖礦」(Mining)。

‧時間戳記:區塊建立的時間,一般以格林威治時間為準。

‧交易內容等資料:各項交易資料,部分加密貨幣允許在此執行程式。

‧上一區塊的Digest:來自上一個區塊的Digest,使其成為一鏈狀結構。

‧當前區塊的Digest:目前該區塊的Digest,必須藉由Nonce使其符合規定的複雜度,否則該區塊會被宣告違法,並連帶使其往後的區塊一起不合法。

由於區塊的雜湊值(Digest,即Hash的輸出結果)與前後區塊密切連繫,所以要對任何的區塊內部資料進行更動,就會影響後續區塊,當區塊長度愈來愈長,要進行變動的難度就會愈來愈高。加上區塊鏈為分散式帳本,每個相關的人都能查看和持有,任何紀錄在鏈上的資料也是同時、同步在進行更新,如此基於多數共識之下也能藉以分辨出不合法的區塊。也就是因為如此的鏈狀結構,使得區塊鏈得以作為驗證技術。

礦工

針對加密貨幣而言,礦工是一批藉消耗電腦資源換取加密貨幣的人員。以比特幣為例,比特幣礦工會替還未確認的區塊進行運算,求出上文提到的隨機值Nonce,以替其進行認證,之後礦工便會向整個比特幣網路廣播該結果,第一個完成的礦工可以得到該區塊發行的新比特幣。

智慧合約

智慧合約為一套以數位形式定義的雙方承諾,只要符合條件,智慧合約可以自動執行,不用人力執行,又具備公信力,使用技術核心的也是區塊鏈,但有別一般使用區塊鏈做為技術核心的差異在於,在智慧合約的內部資料可以存放程式碼,並且能夠執行。以最早推行智慧合約的以太幣來說,在智慧合約的使用上,需要Gas作為手續費,每執行一種函數就會花掉固定的Gas,就以太幣來說,Gas本身要靠以太幣來購買。

Gas是以太坊系統的一個代幣,與比特幣交易費不同的是,比特幣是直接支付比特幣作為轉帳手續費的,以太坊卻是自由訂價,傳送方願意支付的Gas價格越高,礦工從交易中獲得的價值就越大,所以礦工們提出他們執行交易所需的最低價格。就好比同一個案子,願意提出的價碼越高,願意去得標的商家自然就會越多,當然以獲利的角度而言,成本是越低越好,所以一般商家會訂出自己可以接受的最低手續費。

智慧合約雖然可以依照雙方的條件設定自動執行,但能否執行完成,仍要看合約執行狀況而定,且現實世界變化多端的情況,可能無法在同一個區塊鏈反映出來。

在區塊鏈系統上,使用智慧合約的好處包括:

1. 智慧合約部署上區塊鏈後,就無法被修改,避免了合約被竄改的風險。

2. 智慧合約在區塊鏈上是公開的,合約參與者可審查程式碼是否有問題。

3. 只要條件滿足,就無法阻止區塊鏈執行智慧合約,執行效力是絕對的。

不過,相對而言的缺點則是:

1. 由於交易需求不同,並不是所有區塊鏈都適合開發智慧合約。

2. 在智慧合約上的任何錯誤,都無法做修正。

Solidity

「Solidity」是一款可用於不同區塊鏈平台上開發智慧合約的程式語言,以此程式語言所完成的應用程式可視為一份具權威性且不可悔改的交易合約(因為區塊鏈的資料不可更動)。在執行程式時,需要支付特定數量的Gas給礦工。

加密貨幣存在的疑慮

區塊鏈的技術能創造一個隱私、高效、安全的共享價值體系,用白話來說,就是任何人都是中心,這才是「去中心化」的意思,沒有中心,不代表沒有中心。解開這層疑惑之後,就來看看因應而生的一些疑慮。

加密貨幣被盜用的可能

如前面所述,加密貨幣並非實際存放在任何地方,所以不能以常規手法進行偷竊,而且區塊鏈會記錄下每一筆交易,也就是說區塊鏈會記錄下每一筆錢的流向,甚至循線追查貨幣的來源,往上逐漸去追查來源,那麼就不可能會出現「某位址的若干加密貨幣不知去向」這種紀錄。

但即便如此,加密貨幣仍是可以被取走的,被取走的不是貨幣本身,而是更改目標的位址。

加密貨幣在交易中遺失的可能

交易的細節都會記錄在區塊鏈上,不太可能會突然出現加密貨幣不知去向的情況,且加密貨幣在整體的總值是不變的,亦即加密貨幣不會無中生有,也不會憑空消失。

不過,就如同前面所述,加密貨幣是點對點的交易模式,也就是交易的雙方位址間的傳遞,而其中一般消費者並沒有平台來進行,便會經過交易所的平台以作為通路。若是更改「自交易所至目標錢包位址」的指向,加密貨幣就會進入到錯誤的錢包位址中,這在區塊鏈上自然是一份完整的「交易」,但對當事人來說貨幣就是被竊走了。

同樣的手法在近幾年已經在各大交易所上演,駭客入侵交易所的系統,取得相關交易人的私鑰後,將加密貨幣轉入自己的錢包,嚴重的甚至導致交易所破產。

加密貨幣的匿名性用於洗錢的可能

加密貨幣匿名性似乎是洗錢的好選擇,但事實上交易紀錄會存於區塊鏈中,任何有心人都可以查到可疑的加密貨幣被存入特定的錢包位址,對於洗錢這種需要消去紀錄的犯罪手法而言顯得綁手綁腳,一旦追查起來,可能會導致其他潛在的帳號都會被發現。

不過,上述的前提在於已經明確掌握了洗錢的部分事證,並確實地鎖定嫌疑犯,方能發動上述的蒐證。所以,實際上加密貨幣的確可能被當做規避政府監管的手段,畢竟加密貨幣的使用和流向並沒有中央的監管系統,在不知道有犯罪發生的前提下,也無法從區塊鏈紀錄判斷是否發生洗錢情事。

帳戶或交易內的資料可以被更改的可能

更改區塊鏈內的資料相當地困難,且經過比對之後可以找出與其他人所持有帳本的內容不同,帳戶資料內的資料也會因為要維持區塊上的完整性而無法變更。

由於加密貨幣和區塊鏈技術目前仍在開發和改進階段,現階段還有很多不同的問題和攻擊方式可以發掘,正如國際貨幣基金組織(IMF)總裁Christine Lagarde所言「否定加密資產並不明智,而是必須歡迎其潛力,但同時也要承認其中的風險。」

針對加密貨幣常見的攻擊

接下來,介紹幾種針對加密貨幣常見的攻擊手段。

雙重支付攻擊

雙重支付攻擊(Double Spend Attack)讓攻擊者可以控制貨幣的Hash Rate,並將同一加密貨幣資金花費兩次。由於加密貨幣不像具有實體的貨幣,其作為電子檔案是可以被複製的,所以花用這個行為並不會從原持有者身上移除擁有的狀態,並進而將區塊鏈分成兩部分,創建不同的紀錄,通常是具有較少節點的網路可能會被劫持。

如圖2所示,原先的區塊分出了B和C兩區塊,假設由於B先於C被完成,那麼照理說開發B者會得到完成B的賞金,並往下計算區塊D,而區塊C則會變成孤兒區塊(Orphan Block),孤兒區塊上的任何資料都不被承認(因其為最短的分支),倘若區塊B內包含了一筆有關比特幣的交易,那麼在區塊B完成後自然視為完成。但人算不如天算,發生了圖3的事情。

圖2  原先的區塊運作。

如圖3所示,開發區塊C的礦工先於區塊D完成前,搶先完成了區塊E和區塊F兩區塊,使那條分叉成為最長的區塊鏈,此時換區塊B和區塊D變成孤兒區塊。若區塊F內又把區塊B進行交易的比特幣用於進行另一場與區塊B相異的交易,便會達成雙重支付攻擊。由於B和D變成孤兒區塊,其上的任何資料已經失效,那麼在B中原本該到目標位址的比特幣會改成完成F內的交易。而要發動這種攻擊,不可能單靠幸運,靠的是算力(Hash Rate,或稱雜湊率)。

圖3  原先的區塊運作出現問題。

51%攻擊

51%攻擊(51% Attack)是雙重支付攻擊的最糟情況,如果攻擊者的算力提升至整個網路的51%,就能成功發動雙重支付攻擊。雖然這聽上去很恐怖,但實際上51%攻擊有以下的限制:

‧代價太高:挖礦所需的礦機和其他相關設備所費不貲,其他還有諸如降溫設備和場地費用,光是要發動攻擊,就需要大量的金錢投入。

‧對加密貨幣失去信任:發動成功而得到不法利益後,可能造成其他人對該加密貨幣失去信任,最糟的情況會導致加密貨幣價值歸0,使得攻擊的獲利降低。

綜合以上所述,發動51%攻擊的條件不易,對於存在已久的加密貨幣要進行攻擊更加困難,因此多是針對規模尚小的加密貨幣。根據專門報導加密貨幣消息的CryptoCoinsNews,依相關報導指出包括Bitcoin Gold、Litecoin Cash、MonaCoin、ZenCash與Verge等加密貨幣網路都曾遭到51%攻擊。

女巫攻擊

女巫攻擊(Sybil Attack)是指個人試圖透過創建多個帳戶身分,或多個節點或電腦,從而控制區塊鏈網路。原理跟創建多個個人社交媒體帳戶一樣,從而以多數票擊退網路上真實的節點。在這情況下,他們可以拒絕接收或傳輸區塊,從而有效地阻止其他使用者進入區塊鏈的網路。

不過,現在以投票機制為主的區塊鏈網路中,已大量採用反女巫攻擊的方法,比如工作量證明(Proof Of Work)機制,用工作成果來證明完成的工作量,以證明是一個真正的節點,來避免一個參與者有很多帳戶所產生的不公平因素。

針對使用者進行攻擊

傳統的網路釣魚、惡意軟體等,目的在於竊走使用者的私鑰和錢包位址,往往對使用者都十分奏效,亦會讓使用者喪失掉控制權。不過,嚴格來說這並不是藉由區塊鏈技術發動的攻擊,而是常見的網路攻擊手法。

交易時的人為錯誤

嚴格來說這並不是攻擊,但企業中的區塊鏈一旦發生錯誤,即便加密貨幣交易所犯了錯,也無法修正。若是人為為之,便會導致智慧合約被廢棄等無法修正的狀況,尤其智慧合約只要條件達成就能自動履行而且不能反悔。這同時也意味著,合約一旦建立,將幾乎無法撤銷問題、改正錯誤,或者扭轉這些欺詐行為,一旦發生這種情況,合約的資金就永遠鎖定在區塊鏈中。

利用區塊鏈夾帶病毒

將病毒的有效載荷分成K個部分,其中每一個部分看起來都像是一個正常的可執行文件,並不會產生任何入侵感染指標,之後將K個部分分別放入不同的區塊,利用Digest可以便捷地驗證惡意軟體各個組成部分的完整性,且因為區塊鏈上的數據是不可篡改的,該病毒一旦寫上區塊鏈網路,就沒有辦法移除。不過,交易中能發送的數據量非常小,嵌入的量實在有限,且各個交易都有其固定的格式,如此安插病毒載體的部分很可能會被發現。

小心Solidity語法漏洞

Solidity是一款用於不同區塊鏈平台上開發智慧合約的程式語言,特色是能夠引用和利用其他外部合約的程式碼。合約也會被用來處理以太幣,因此通常會將以太幣發送給各種外部使用者的位址,但由於一些語法上的問題,Solidity擁有一些編譯過程會出現的漏洞,大部分和Fallback有關,接下來將說明常見問題,並提供解決方法。

重入漏洞(Reentrancy)

Solidity允許使用者的合約呼叫其他的外部合約,或將其發送到自己合約的位址,該操作需要合約公開給其他的外部合約進行引用。這些嘗試呼叫外部合約的函數可能會被打斷,合約便會開始執行Fallback函數,其中包括呼叫自己原本的合約。

Fallback函數是一個特殊函數,不會出現在智慧合約中。在合約中若出現呼叫不存在函數時,Fallback就會啟動,或者呼叫函數時沒有帶入配合的資料時也會啟動。簡單來說,就是呼叫函數時失敗的自動處理程序。Fallback函數可大可小,不過過多的執行會導致Gas的消耗。當合約將以太幣發送到未知位址時,就可能會發生此種攻擊。攻擊者可以在Fallback函數中建構出一個可能包含惡意程式的合約,最簡單的方法就是建立一個迴圈,讓迴圈反覆進行。

解決方法在於,要將以太幣發送給外部合約時避免使用call函數,因為其允許將剩餘的Gas全部用來繼續呼叫外部的函數(例如Fallback函數)。一般正常來說,轉帳時合約應只會發送出特定數量的Gas,量不至於足以使該位址或外部合約呼叫另一份合約。或者,事先就決定好發送Gas的數量,如果執行到該有的數量上限時,便會停止運作,不再繼續執行。

簡而言之,重入漏洞(Reentrancy)是藉由Fallback函數的特性,以重複呼叫的方式,反覆地獲取同一合約裡的以太幣,直至貨幣不足或是Gas耗盡。

外部合約引用

以太坊平台的好處之一是能夠重複使用智慧合約的程式碼,並與已發布在網路上的其他合約交互進行使用。因此,任何合約都可以引用其他外部合約的公開函數,並且在一般執行中使用外部合約的函數來與其他合約交互使用。這些外部合約的函數呼叫能夠以一些不易察覺的方式來掩蓋惡意行為者的意圖。

在Solidity中,無論合約位址上的程式碼是否表示正在使用的合約類型,都可以將任何合約位址進行轉換。這意謂著,任何看到來自外部合約的函數引用,可能不如所見到的那麼單純,特別是當合約的使用者試圖隱藏惡意程式碼時,例如利用密碼的技術將一串惡意程式碼加密,明眼看過去不會有甚麼問題,但引用該程式碼後,便會解密並執行。

解決方法不易,除非能預估攻擊者的手法,否則很難在第一時間進行反制;另一種解決的方法是使用new關鍵字來創建合約,這樣引用合約的一個函數就會在部署時創建,並且部署者無法在不修改智慧合約的情況下使用其他任何東西替換合約。

拒絕服務

拒絕服務(DoS)無處不在,藉由癱瘓目標提供的服務,讓真正需要該服務的客戶沒辦法正常地使用,而在以太坊平台裡,手法與其說是拒絕服務,其實就是惡意操作的資源消耗。簡單來說,就是對以太坊的智慧合約進行DoS攻擊,導致以太幣和Gas的大量消耗,更嚴重的是讓原本的合約內的程式碼邏輯無法正常運行。

可預測的隨機處理

虛擬隨機(Pseudorandom)一直都存在於現代電腦系統中,比如C語言中的rand()就不是完全的隨機,但是在資料大部分開放的區塊鏈網路中,像是在以太坊智慧合約編寫時,任何與隨機相關的處理就顯得重要,由於任何有心人都能查看區塊鏈上的資料或合約內容,合約中的任何參數、函數都能在區塊鏈上分析得到。如果合約的程式碼沒有考慮到區塊鏈公開的問題,而隨意地使用可預測的隨機數,可能會被攻擊者惡意利用來進行「作弊」。還有,一些人可能在建立合約時喜歡用任意區塊的編號得出一個隨機Digest,但應切記不應使用當前區塊編號做為隨機數。

BEC合約漏洞

BEC是代幣(Token)之一,BEC漏洞實質上是一個算法上下溢出漏洞。該漏洞的原理在於,當合約在進行提款或是轉帳功能時,一般來說會對使用者位址的餘額進行操作,如果餘額的操作手段沒用SafeMath(官方發行的函數庫)或是程式中沒有規範輸入值的區間,則攻擊者可以經過設計將轉帳的扣款金額弄成其他數值,以即將轉出金額弄成很大的數值,導致合約運行時憑空產生很多代幣,或用戶憑空從合約中提出很多不屬於他的餘額,如圖4所示。

圖4  導致溢出可能。

案例探討說明

科技在進步,犯罪手法也跟著科技潮流手法不斷換新,以下先來看一段程式碼。

圖5是某使用以太幣進行交易的圈子所使用的程式碼,簡單概括一下,函數withdrawRewardFor()的功用在於合約計算應該退給使用者的金額,並呼叫函數payOut()執行轉帳,值得注意的是一般在執行呼叫call.value時,會把所有的Gas傳送到合約地址上並執行預設函數,搭配下面執行的另一個函數便會產生一個問題。

圖5  預設提領的程式碼。

而圖6是某個合約中預計把資金分裂出去呼叫的函數,簡單來說,使用者提出分裂後,先會呼叫splitDAO()開始進行,之後便會呼叫withdrawRewardFor()執行計算,再從payOut()呼叫call.value傳送金額給使用者。

圖6  交易方使用的程式碼。

乍看之下,程式並沒有錯誤,問題在於call.value即便回傳的布林值(Boolean)為True,也並不代表執行成功,也可能是完成了「因為呼叫call.value失敗所產生的Fallback函數」,亦即回傳True代表執行成功,但不知道成功的是call.value,還是call.value的Fallback函數,而且該Fallback函數是建立在與splitDAO()有關的合約上,此時使用call.value的Gas便已經發放,且將會有足夠的Gas執行任何操作。

今天倘若先建立了一個合約A,這個合約擁有一個Fallback函數,它的作用是去呼叫splitDAO(),而splitDAO()設定的位址即為合約A。結合以上的兩個程式碼,開發者先是在函數withdrawRewardFor()中把金額退還給了使用者,然後在Fallback函數之後將使用者的餘額設置為0。那麼如果攻擊者在withdrawRewardFor()和餘額設置為0之間在此呼叫withdrawRewardFor,將會再次向攻擊者提交的地址轉移帳戶金額。利用call.value的機制,在合約中再次呼叫轉帳申請,由於上一次轉帳申請的餘額還沒有更新,所以第二次也會成功。如圖7所示,相當於在迴圈中重複呼叫自己,有如程式設計中的遞迴,直到目標位址的以太幣被提領完畢。

圖7  運作流程(左為正常情況,右為會出問題的迴圈)。

<本文作者:台灣E化資安分析管理協會(ESAM, http://esam.nctu.me/esam/) 2018年創立,從事E化資訊安全的分析管理與學術研究,並與政府、產學及國際資安機構交流與合作,推廣資訊安全應用與發展,協助企業、產業評估資安分析與風險為宗旨。中央警察大學資訊密碼暨建構實驗室(ICCL)1998年12月成立,目前由王旭正教授領軍,並致力於資訊安全、情資安全與鑑識科學,資料隱藏與資料快速搜尋之研究,以為人們於網際網路(Internet)世界探索的安全保障(https://sites.google.com/site/iccltogether/)。>

 


追蹤我們Featrue us

本站使用cookie及相關技術分析來改善使用者體驗。瞭解更多

我知道了!