十、以太坊安全之 漏洞清單
遵循 ERC20 标準開發的 token 合約隻能說完成了代币合約的基本功能,并且便于使用。但區塊鍊甚至以太坊畢竟也是個新鮮事物,是以随着時間過去,以太坊和 Solidity 語言本身固有的缺陷,以及相關安全規範不足的問題逐漸暴露出來,再由于區塊鍊技術的不可撤消性,這就要求我們在開發用于生産環境的智能合約時,還要較多考慮一些安全方面的問題。
本節先簡單羅列下以太坊自運作以來,由于漏洞已經爆出的一些重大安全事件。
以下内容轉自 以太坊目前已知安全問題總結,如何打造安全的以太坊智能合約。
智能合約語言 Solidity 自身與合約設計都可能存在漏洞。如果智能合約開發者疏忽或者測試不充分,而造成智能合約的代碼有漏洞的話,就非常容易被黑客利用并攻擊。 —— 衆享比特
以太坊Ethereum是一個開源的有智能合約功能的公共區塊鍊平台。區塊鍊上的所有使用者都可以看到基于區塊鍊的智能合約。但是,這會導緻包括安全漏洞在内的所有漏洞都可見。智能合約語言 Solidity 自身與合約設計都可能存在漏洞。如果智能合約開發者疏忽或者測試不充分,而造成智能合約的代碼有漏洞的話,就非常容易被黑客利用并攻擊。并且越是功能強大的智能合約,就越是邏輯複雜,也越容易出現邏輯上的漏洞。
1、以太坊的安全漏洞
如果說區塊鍊也有 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,以太坊用于開發智能合約的類java-script語言,被發現有一個安全漏洞,當以太坊合約進行互相調用時,它們自身的程式控制和狀态功能會丢失。因為它能切斷以太坊智能合約間的溝通,就像太陽風暴能切斷地球的通訊裝置一樣,可以影響整個以太坊。 |
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的消耗,如果有必須使用大量計算的地方,盡量将其放到鍊下去處理。
- 如果可能,合約邏輯應該避免依賴于合約餘額的确切值,因為它可以被人為地操縱,比如攻擊者将目前合約位址發送到其他合約的
方法,則目前合約将不得不接受是以轉移過來的 ether。selfdestruct
- 在智能合約中添加一個函數,執行一些自我檢查,如“有沒有以太洩漏?”。如果自檢失敗,智能合約會自動切換到某種“故障安全”模式,例如,禁用大部分功能,将控制交給固定和可信的第三方,或者将智能合約轉換成簡單的“把我的錢還給我”智能合約。
- 目前以太坊的 Solidity 問題的确挺多,類似的合約語言還有 Serpent,而 Synereo 的 Rholang 在安全方面會美好一些。
thead {font-weight: bold; }
.head1 {min-width: 28px; text-align: center;}
.head2 {min-width: 110px; text-align: center;}
.head3 {text-align: center;}
tbody tr:nth-child(2) {background:RGB(248, 248, 248);}
tbody tr td:first-child {text-align:center;}
tbody tr td:nth-child(2) {text-align:center;}