「深度」智能合約及Dapp安全簡介

「深度」智能合約及Dapp安全簡介


哈嘍!

我們是Coin Link X【幣聯萬物】生態社區旗下的新媒體運營團隊,我們專注於以輕鬆、高效的方式為您提供專業、有趣的幣圈知識,歡迎關注以下微信公眾號、頭條號、微博號等:

【幣圈入口】—— 致力於區塊鏈及幣圈基礎知識的傳播和普及

【幣鏈3.15】—— 曝光行業黑幕,揭露幣圈騙局,協助大家維權

【笑談幣圈】—— 這裡有幣圈搞笑、好玩的段子、圖片、表情包等

【幣人幣事】—— 細數幣圈風雲人物,那些你遇到或未遇到的奇人軼事

【人人比特】—— 加密數字貨幣的佈道者,與您一起探討如何炒幣、玩幣

導讀:各個公鏈上的智能合約和Dapp數量在高速發展的同時,也隱藏著許多致命的風險,本文結合區塊鏈的特性,為廣大智能合約和DAPP開發者提供忠實的安全方面建議。

智能合約和dapp的開發屬於新的範式,開發的方式與以前會有所不同。


「深度」智能合約及Dapp安全簡介



“敏捷開發”的格言在這個新範式中好像不起任何作用了,這類項目的開發會有一定的風險,這要求我們採用緩慢而有條理的方法來開發我們的應用程序,在設計和編碼時儘量謹慎和考慮周全。

開發時也不能讓自己承受過多的壓力,比如制定嚴格的期限等。

如果把大多數傳統的apps類比於社區診所,那麼區塊鏈可以說是急診室。有些很小的問題,一旦上鍊的話,就會變得很難解決,你必須考慮到所有可能的負面結果,如果沒有這麼做,你可能會面臨非常可怕的後果。

所以在我開始具體的內容之前,我必須要重申一下區塊鏈開發方面的特點,這些迫使我們開發時要非常小心。


「深度」智能合約及Dapp安全簡介



所有代碼都是公開的

首先,區塊鏈的代碼是開源的,任何人都可以看到你寫的代碼,所以智能合約中不應記錄敏感的個人信息。不然,你就可以進行用戶的鏈上行為分析,這對於小白用戶來說可能聽起來不太好,因為他的歷史行為暴露在了全世界面前。


這就導致智能合約及其相關存儲功能只能存儲合同正常運行所必需的信息。

其次,最最重要的是,所有源代碼都公開可見,這意味著在地下工作的明星黑客有充足的時間和自由,來梳理你的每一行代碼,尋找其中的漏洞,代碼將無處可藏。

Gas 限制

我相信大多數人都知道,以太坊的是有Gas費的,Gas費些許的昂貴,並且還有一定的限制!如果智能合約中的邏輯可以導致大量Gas消耗,則會出現嚴重的問題。循環調用是這種情況的常見原因。

最後也是最重要的一點是:

不可篡改特性

智能合約代碼都是完全根據最初的邏輯執行,都不想重蹈The DAO級別的硬分叉悲劇。

區塊鏈開發的特點是,合約一旦部署,一切都將不可篡改。不可篡改的優點是讓我們可以高枕無憂地相信智能合約。我們首次將信任編程到代碼中。陌生人之間可以信任代碼,而不是彼此建立信任。我們慢慢的開始相信智能合約,它不會騙人,也不會在任何時候做出格的事情。

對我來說,我會以非常開放的心態擁抱全球的區塊鏈霸主。並且作為工程師,我也會努力去實現這個信任社會,但是這個信任社會也有致命的問題。

設想一下,如果我們家的技術文盲奶奶不小心把她的google搜索痔瘡膏的信息發佈到了Facebook上,這不會是大問題,可以刪掉。但如果她在某個有漏洞的智能合約上暴露了自己的私鑰,那我們就無能為力了,她精通技術的侄子也沒有任何辦法,區塊鏈瀏覽器中歷史記錄將無法刪除!

在寫代碼的時候,我們必須假設每個用戶都是技術文盲,並百分百地確保函數的正確調用,執行能夠操作無誤,你永遠都不會知道,有多少人盯著你錢包地址上的數百萬美金。

接下來我將介紹一些準備好的漏洞示例,並且進行一些練習,讓每個人都參與進來。以便我們在今後在寫代碼時能夠避免Dapp和智能合約的漏洞。

「深度」智能合約及Dapp安全簡介


實際案例推薦

我們來看第一個案例,讓我們從一些背景開始。

· 這是一個去中心化的遊戲平臺

· 它的應用程序都是基於瀏覽器的

· 遊戲開發者可以公開發布他們的遊戲(在以太坊網絡上運行的dapps)

· 玩家可以註冊dapp並從選擇各種遊戲(用ETH購買虛擬商品)

· 註冊時會幫你創建新的錢包(這個案例不需要Mist 或Metamask)

· 錢包密鑰存儲在玩家的瀏覽器中,用於驗證和支付。

是的,這似乎是開發人員通過平臺進行發佈,並有效連接玩家的好地方。

不幸的是,有一款叫HODL QUEST的遊戲在發佈後,用戶下載它時,他們錢包中的以太幣數量就開始減少。

玩家的以太幣去哪了呢?讓我們先來看一下平臺的一些情況:

· 這個問題是幾小時前發佈的新遊戲HODL QUEST引起的

· 首次打開遊戲後,錢包的資金幾秒鐘就消失了

·在遊戲註冊期間,開發人員在平臺內的表單中輸入dapp的名稱,智能合約地址和URL

· 該平臺將遊戲iframe嵌入到dapp中,同時在頁面頂部顯示遊戲名稱

· 你可以開始看看它的發展方向......經過進一步的檢查,我們發現HODL QUEST遊戲的開發者在註冊過程中為遊戲標題注入了一個內聯腳本。仔細觀察遊戲html代碼,我們發現了這樣的事情:

HODL QUEST

用戶的瀏覽器插入了遊戲標題的javascript片段,並將用戶的私鑰發到給攻擊者遠程服務器上。

這只是我們寫Dapp時可能出現的眾多問題之一。

以下我列舉的是,在構建項目時要記住的事項清單:

•保護錢包和私鑰:如果用戶的錢包受到損害,那就game over了,所以處理這些敏感信息時需要特別小心。

•保護用戶信息:用戶不希望他們的個人數據暴露在世界各地,開發時要確保用戶數據不被洩露。

•明智地評估需要存儲在區塊鏈或服務器中的內容,只能包含智能合約運行所必需的數據

•使用HTTPS:這是標準做法,應該是顯而易見的

•.gitignore敏感文件:保護自己免於意外洩露漏洞的另一種方法

•不要在代碼中插入訪問/ API密鑰

•在dapp中執行關鍵/風險操作時要進行雙重認證:在區塊鏈上採取的操作是不可變的,因此鏈下的安全驗證非常重要

DAPP的安全性與智能合約的安全性一樣重要,希望廣大開發者始終牢記在心。


「深度」智能合約及Dapp安全簡介



智能合約競爭條件

再來講講競爭條件,什麼是競爭條件?就是是電子設備,軟件或其他系統中的輸出取決於其他不可控事件的順序或時間一種行為。當事件沒有按程序員的意圖發生時,它就變成了一個bug。這是以太坊智能合約中許多漏洞的根源

在以太坊智能合約中出現競爭條件的方式有幾種。在這篇文章中,我們將關注兩種常見情況。重入和交易順序依賴。

重入

如果計算機程序可以在執行過程中被中斷,則可以在其先前的調用完成執行之前安全地再次調用(“重新輸入”),這被稱為可重入計算機程序。在對其他合同進行外部調用時,這可能會顯示在智能合約中,因為它們可能會在原始調用完成之前回調到原始函數。你可能會問,這怎麼可能?

輸入fallback 函數,這些函數是在將Ether發送到合約時調用的功能,而不提供要調用的函數名稱。

「深度」智能合約及Dapp安全簡介

在這個例子中,當withdraw函數使用address.call.value()方法發送ether時,它會觸發BankRobber的fal’lback函數,然後可以再次調用withdraw方法。正如您所看到的,這將導致智能合同一次又一次地發送以太可能會耗盡所有以太幣!

「深度」智能合約及Dapp安全簡介

從上圖中可以看出,有許多不同的方式可以發送以太幣,但大多數情況下,都推薦使用address.transfer。這是因為如果交易耗盡所有的2300 gas,就會回滾。這樣,如果惡意合同試圖重新簽訂合同,gas將用完,整個交易將被還原。

在某些情況下,使用發送或回調是有意義的,但在使用這些時需要格外小心,因為只有在發送以太幣感到非常滿意時,才會出現這種情況。99%的時候,轉移是正確的路徑。

防止重入的另一種方法是在進行外部調用之前更新狀態並在合同中執行檢查,以確保狀態代表即將執行的事務。

「深度」智能合約及Dapp安全簡介


打包頭部交易(交易順序依賴)

另一種情況是競爭條件依賴,讓惡意的交易被優先打包,這是區塊鏈的開源性質決定的。如果在智能合約中運行競價或類似機制,黑客可能會通過操縱gas價格,礦工打包交易時會在交易池中選擇價格高的進行打包。在這段時間內,其他惡意行為者可以監控併發送惡意交易,來破壞已經發送的出價交易。礦工則會對區塊中的交易價格進行重新排序,這就造成惡意交易被優先打包。

有幾種不同的方法可以防止像這樣的操縱。一個是把交易批量打包,另一個方法是披露投標人發送其出價的哈希值,在確認之前識別是不是惡意交易。

讓我們來看看另一個例子

這個智能合約是一個遊戲,用戶可以將以太幣送到智能合約中成為新的國王。當一個新人成為國王時,老國王就會收到智能合約中的以太幣。你能找到這個漏洞嗎?

「深度」智能合約及Dapp安全簡介

這是Ethernaut的一個很好的例子,它開展了探索智能合約安全的練習。

這些示例表明,在進行外部調用時,絕不應該假設您調用的智能合約是可信的。始終注意防止攻擊者可能嘗試的所有可能的負面結果。

「深度」智能合約及Dapp安全簡介


fallback函數

fallback函數很有用,因為它們包含在將Ether發送到您的合同時調用的代碼。但他們無法處理一切。

首先,當從fallback函數觸發時,回退功能只能訪問2,300 gas,因此邏輯需要非常簡單,以免發生gas錯誤。

// example of a fallback function when

// you don't want Ether to be sent to a contract

function () payable {

revert()

}

有一個問題!當以太幣被強制發送到合約時,後備功能不會觸發

contract ForceSend() {

function ForceSend() {

// sends ETH to victim without triggering the fallback function

function destroy() {

selfdestruct(victim);

}

}

函數將智能合約的以太幣發送到受害者地址。此發送不會觸發合同中的回退功能。接收免費以太是很好的,但正因為如此,你需要避免直接檢查合同的餘額並期望它是一個特定值,因為它實際上可能比你想象的更大!

整數運算

與大多數現代架構不同,EVM不處理浮點數或算術運算。所有數字存儲和算術都用整數處理。這是什麼意思?這意味著您的合同中沒有任何意義,您可以將任何內容存儲為小數或執行通常會返回小數的操作,例如查找百分比等。讓我們看一個例子。

想象一下,您正在創建一個代幣銷售智能合約,根據銷售過去的時間為買家提供獎勵購買。它可能看起來像這樣。

/// snippet from contract code

function calculatePrice() returns (uint256) {

uint percentTimePassed = (now - startTime)/(endTime - startTime);

uint price = (1-percentTimePassed)*basePrice + basePrice;

return price;

}

正如您所看到的,用傳統語言,通過的時間百分比將計算為0到1之間的小數,然後返回價格。

不幸的是,這不適用於整數運算。如果操作操作不正確,可能某些不正確的百分比會導致嚴重問題的情況。

在Solidity中,你必須做這樣的事情:

/// snippet from contract code

function calculatePrice() returns (uint256) {

uint percentTimePassed = 100*(now - startTime)/(endTime - startTime);

uint price = ((1-percentTimePassed)*basePrice)/100 + basePrice;

return price;

}

百分比計算為0到100之間的整數,應用於基本價格,然後除以100以將“小數位”固定到正確的點。這是計算百分比的一種粗略方式,因為它犧牲了一些精度,但是根據EVM的運行方式是必要的。您可以通過乘以100的較大倍數來獲得更好的精度,但這是一個取決於合同背景的決定。

「深度」智能合約及Dapp安全簡介


整數溢出/下溢

根據維基百科,當算術運算嘗試創建一個數值超出可以用給定位數表示的範圍 - 大於最大值或低於最小可表示值時,就會發生整數溢出。大多數語言都有解決此問題的方法,但Solidity無法自行處理溢出檢查。這導致過去在區塊鏈上出現一些智能合約的問題,但有很多方法可以解決這個問題。以下是使用Solidity添加的示例:

function add(uint a, uint b) {

res = a + b

if (res-b == a) && (res>b || res==b) {

// the operation was safe

} else {

// overflow

}

}

這通過確保結果沒有包圍變量所保持的最大值來檢查加法運算的溢出。減法,乘法和除法需要類似的檢查。

漏洞 3

你能找到智能合約中的錯誤嗎?

uint[] public bonusCodes;

function pushBonusCode(uint code) onlyOwner {

bonusCodes.push(code);

}

function popBonusCode() onlyOwner {

require(bonusCodes.length >= 0);

bonusCodes.length--;

}

function modifyBonusCode(uint index, uint update) onlyOwner {

require(index < bonusCodes.length);

bonusCodes[index] = update;

}

此契約具有一個存儲數組,其長度字段可以遞減到0.這會導致算術下溢,從而有效地禁用Solidity的數組邊界檢查。因此,在溢出寫入數組之後可以用來覆蓋位於數組之後的任何存儲元素 - 包括所有映射!

在開發的時候,我們並不能確定,有哪些沒有考慮到的微小的點,單這些可能是導致歸零的重大問題,在文中舉的案例中,就導致用戶平均損失了數百萬美元。

我們所能做的最好的事情就是遵循所有現有的應用程序和智能合約範式,並且要要進行廣泛測試,以及要讓專業的安全人員幫我們審核代碼。

未來,讓我們一起共建智能合約的功能和安全性!


分享到:


相關文章: