如何打造安全的以太坊智慧合約

众享比特發表於2018-03-14

以太坊Ethereum是一個開源的有智慧合約功能的公共區塊鏈平臺。區塊鏈上的所有使用者都可以看到基於區塊鏈的智慧合約。但是,這會導致包括安全漏洞在內的所有漏洞都可見。智慧合約語言 Solidity 自身與合約設計都可能存在漏洞。如果智慧合約開發者疏忽或者測試不充分,而造成智慧合約的程式碼有漏洞的話,就非常容易被駭客利用並攻擊。並且越是功能強大的智慧合約,就越是邏輯複雜,也越容易出現邏輯上的漏洞。

如何打造安全的以太坊智慧合約

以太坊的安全漏洞

如果說區塊鏈也有 315,那麼以太坊想必榜上有名。以太坊自執行以來多次爆出過由於漏洞造成的重大安全事件。

2016 年 6 月 17 日,區塊鏈出現了歷史上沉重的一次攻擊事件。由於以太坊的智慧合約存在著重大缺陷,區塊鏈業界最大的眾籌專案 TheDAO(被攻擊前擁有約 1 億美元的資產)遭到攻擊,導致 300 多萬以太幣資產被分離出 TheDAO 資產池。

2017 年 7 月 21 日,智慧合約編碼公司 Parity 警告其 1.5 版本及之後的錢包軟體存在漏洞,據 Etherscan.io 的資料確認,有價值 3000 萬美元的 15 萬以太幣被盜。2017 年 11 月 8 日,Parity 錢包再出現重大 bug,多重簽名漏洞被駭客利用,導致上億美元資金被凍結。

以太坊開源軟體主要是由社群的極客共同編寫的,目前已知存在 Solidity 語言漏洞、短地址漏洞、交易順序依賴、時間戳依賴、可重入攻擊等漏洞,在呼叫合約時漏洞可能被利用,而智慧合約部署後難以更新的特性也讓漏洞的影響更加廣泛持久。

據有關調查統計,以太坊主要漏洞情況描述如下表:

序號 漏洞名稱 漏洞描述
1 The DAO 漏洞

執行在以太坊公有鏈上的 TheDAO 智慧合約遭遇攻擊,該合約籌集的公眾款項不斷被一個函式的遞迴呼叫轉向它的子合約,涉及總額三百多萬以太幣。程式碼中透過 addr.call.value() 的方式傳送以太幣,而不是 send(),這給駭客留下了空間。駭客只需要製造出一個 fallback 函式,在該函式里再次呼叫 splitDAO() 即可。

2 Parity 多重簽名錢包合約漏洞 使多重簽名的智慧合約無法使用,核心問題在於越權的函式呼叫。駭客間接呼叫了初始化錢包軟體的庫函式,讓自己成為多個 Parity 錢包的新主人。駭客呼叫了一個叫做 initWallet() 的函式,它沒有檢查以防止攻擊者在合同初始化後呼叫到 initMultiowned(),這個函式使得這個合約的所有者被改為攻擊者,相當於從 Unix 中獲得了 root 許可權。
3 Parity 多重簽名錢包提款漏洞 錢包的提款功能都失效,150 多個地址中超過 50 萬個 ETH 被徹底凍結,漏洞使得駭客能透過庫函式成為庫的主人,然後呼叫自殺函式報廢整個合約庫。
4 太陽風暴

Solidity 是以太坊用於開發智慧合約的類 JavaScript 語言,被發現有一個安全漏洞,當以太坊合約進行相互呼叫時,它們自身的程式控制和狀態功能會丟失。因為它能切斷以太坊智慧合約間的溝通,就像太陽風暴能切斷地球的通訊裝置一樣,可以影響整個以太坊。

5 以太坊程式語言 Solidity漏洞 影響了智慧合約中一些地址以及資料型別,大多數受影響的合約將無法被撤回或更改。
6 智慧合約 Fallback 函式 當呼叫某個智慧合約時,如果指定的函式找不到,或者根本就沒指定呼叫哪個函式(如傳送以太幣)時, fallback 函式就會被呼叫,駭客可以利用 fallback 函式做出很多危害系統的事情。
7 智慧合約遞迴呼叫recursive

使用者取款的程式碼存有嚴重的遞迴呼叫漏洞,該使用者可輕鬆地將你賬戶裡的以太幣全部提走。

8 呼叫深度限制call depth 以太坊虛擬機器 EVM 中一個智慧合約可以透過 message call 呼叫其它智慧合約,被呼叫的智慧合約可以繼續透過 message call 再呼叫其它合約,甚至是再呼叫回來(recursive)。駭客可以利用巢狀呼叫的深度被限定 1024 發動攻擊。
9 以太坊瀏覽器 Mist 這個漏洞來源於底層軟體框架 Electron,使得加密數字貨幣私鑰安全受影響。
10 區塊節點漏洞

來自於以太坊區塊鏈上 2283416 區塊節點的漏洞,主要造成了包括 Geth 在內的所有基於 Go 語言編寫的以太坊 1.4.11 版本客戶端出現記憶體溢位錯誤,並阻止了進一步挖礦。

11 日食攻擊eclipse attack 日食攻擊是其他節點實施的網路層面攻擊,其攻擊手段是囤積和霸佔受害者的點對點連線時隙slot,將該節點保留在一個隔離的網路中。這種型別的攻擊旨在阻止最新的區塊鏈資訊進入到日食節點,從而隔離節點。
12 以太坊短地址漏洞 由於 EVM 並沒有嚴格校驗地址的位數,並且還擅自自動補充消失的位數,使得合約多傳送很多代幣出來。
13 Geth 客戶端 DoS 攻擊漏洞

大約 75% 的以太坊節點都在執行 Geth,這個漏洞可能會使那些執行相容拜占庭的版本的節點在硬分叉之後更加容易遭受 DoS 攻擊。

14 浪子合約漏洞 交易資金因為漏洞返還給所有者、交易者過去傳送給乙太網的地址,以及特定地址。這種漏洞就像是空手套白狼,買家得到商品,而賣家無法得到加密貨幣。
15 自殺合約漏洞 智慧合約的擁有者可以在以太坊發生故障時選擇退回,類似於微信中的撤回選項。但是這個指令也可以被其他人執行,使得交易失敗。
16 貪婪合約漏洞

這是指那些永遠停留在以太坊的智慧合約,上述的 Parity 漏洞正是一種貪婪合約,它會把智慧合約所涉及的商品以及加密貨幣鎖定在以太坊中,交易雙方均無法得到,也不能取消。

17 遺囑合約漏洞 在那些已完成或者被關閉的智慧合約中,雖然它們的程式碼和全域性變數被清除了,但是其中一部分仍然在繼續執行。遺囑合約和貪婪合約一樣,均是由以太坊的錯誤引起,目前並不能被駭客利用。
18 交易順序依賴性 一筆交易被傳播出去並被礦工認同包含在一個區塊內需要一定的時間,如果一個攻擊者在監聽到網路中對應合約的交易,然後發出他自己的交易來改變當前的合約狀態,例如對於懸賞合約,減少合約回報,則有一定機率使這兩筆交易包含在同一個區塊下面,並且排在另一個交易之前,完成攻擊。而這個攻擊者甚至可以自己直接參與挖礦,並提出更高的 gasPrice 來激勵礦工包含這筆交易。
19 時間戳依賴性

有一部分智慧合約使用區塊的時間戳來作為某些操作的觸發條件。通常來說都是使用礦工的本地時間作為時間戳,而這個時間大約能有 900 秒的範圍波動,當其他節點接受一個新區塊時,只需要驗證時間戳是否晚於之前的區塊並且與本地時間誤差在 900 秒以內。一個礦工可以透過設定區塊的時間戳來儘可能滿足有利於他的條件,從中獲利。

20 可重入性 當一個合約呼叫另一個合約的時候,當前執行程序就會停下來等待呼叫結束,這就導致了一個可以被利用的中間狀態。利用合約存在的中間狀態,當一個合約還沒有呼叫完成時發起另一個呼叫交易,即可完成攻擊。
21 挖礦中心化 以太坊前 3 大礦商控制著超過 50% 的算力,存在聯合作惡的風險。

上述漏洞目前已經廣泛存在以太坊網路中,2018 年 2 月 24 日,新加坡和英國幾位研究員指出,3.4 萬多份以太坊智慧合約可能存在容易被攻擊的漏洞,導致數百萬美元以太幣暴露在風險中,其中 2365 份屬於著名專案。

鑑於以太坊其執行時間還不到 3 年,如上漏洞可能只是其所有漏洞的冰山一角,為保證業務在區塊鏈上安全可靠執行,保護數字資產的安全,採用以太坊做為區塊鏈技術方案時必須對智慧合約程式碼進行充分測試。

如何構造安全的智慧合約

在構造智慧合約時,國內知名的區塊鏈獨立技術方案提供商眾享位元的安全建議如下:

  • 限制在智慧合約中儲存以太坊的數量。如果智慧合約原始碼、編譯器或者平臺有問題,這些資金可能丟失。
  • 儘可能保證智慧合約中的功能小而模組化。原始碼質量一定要得到保證(比如限制區域性變數的數量,函式的長度),程式註釋儘量完整,以便方便日後的維護和增加程式碼的可讀性。
  • 儘可能減少交易中 GAS 的消耗,如果有必須使用大量計算的地方,儘量將其放到鏈下去處理。
  • 在智慧合約中新增一個函式,執行一些自我檢查,如“有沒有以太洩漏?”。如果自檢失敗,智慧合約會自動切換到某種“故障安全”模式,例如,停用大部分功能,將控制交給固定和可信的第三方,或者將智慧合約轉換成簡單的“把我的錢還給我”智慧合約。

相關文章