合約之熵,安全之殤——區塊參數依賴

合約之熵,安全之殤——區塊參數依賴


針對區塊鏈安全問題,成都鏈安科技團隊每一週都將出智能合約安全漏洞解析連載,希望能幫助程序員寫出更加安全牢固的合約,防患於未然。

引子: 橘生淮南則為橘,生於淮北則為枳,葉徒相似,其實味不同。所以然者何?水土異也。

—— 《晏子春秋·雜下之十》

只要是儲存在storage裡面,存在於區塊鏈上的變量,尤其是狀態變量,由於區塊鏈公開的特性,都是可以通過不執行合約直接從外部讀取的。因此,將隱私信息,不可公開的數據儲存在智能合約中是非常不安全的做法。

即使進行有意或者無意的此類操作,都要及時附加相應的加密處理,避免因為對於可見性說明符的片面理解而留下安全隱患。全面理解代碼技術細節,融會貫通互聯網安全知識,才能安全應用區塊鏈技術。

本期話題:機制依賴參數主導,礦工操縱投機取巧

山竹過境,氣候入秋,想必大家都感受到了久違的一絲涼意,這倒也與區塊鏈產業的“寒冬”有些應景。不過更令人心寒的還是近期以太坊遊戲的事故頻發。例如,FOMO3D最近的第二次開獎,獲獎者仍然是黑客,使用的手段依然是我們在第六期遊戲合約漏洞總結當中提到的“類似競態條件利用的阻塞交易手法”。還有我們之前在快訊中提到的Mycryptochamp這個遊戲,其隨機數(或者說熵的變量)生成機制依賴的是可預測的參數,導致投機者輕易獲取空投,影響遊戲公平性。

這些遊戲的機制都依據以太坊的特性來設計隨機數的產生,但是設計理念卻是在沒有理解這些特性的基本原理來定製的。因此如火如荼短時間炒作後,在無法實現公平遊戲的情況下“迅速降溫”。

本期,我們將重點分析遊戲過於依賴區塊參數設計而產生的兩種漏洞——時間戳依賴和區塊哈希依賴。

基礎小知識:

什麼是區塊參數?

以太坊的實現機制與比特幣有很大的差別,以太坊的每個區塊頭多了一些以太坊自身特殊的字段,用來表示區塊的屬性值,以太坊智能合約可以通過以太坊提供的接口讀取這些屬性值:

block.blockhash(uint blockNumber) returns (bytes32):指定區塊的區塊哈希——僅可用於最新的 256 個區塊且不包括當前區塊;而 blocks 從 0.4.22 版本開始已經不推薦使用,由 blockhash(uint blockNumber) 代替

block.coinbase (address): 挖出當前區塊的礦工地址

block.difficulty (uint): 當前區塊難度

block.gaslimit (uint): 當前區塊 gas 限額

block.number (uint): 當前區塊號

block.timestamp (uint): 自 unix epoch 起始當前區塊以秒計的時間戳

now (uint): 目前區塊時間戳(block.timestamp)

需要注意的是:在同一個塊中,每筆交易讀取的區塊參數都是一樣的。

什麼是熵?

熵(entropy)的概念最早起源於物理學,用於度量一個熱力學系統的無序程度。在信息論裡面,熵是對不確定性的測量。

所以在以太坊中,熵(entropy)也就是我們所說的隨機性(randomness)。

對於一個以隨機性為核心的遊戲合約,熵的變量的計算尤為重要。

事故頻發 問題凸顯

上面講到的MyCryptoChamp體現,其合約中RandMod函數使用私有變量randNonce和父塊哈希作為參數生成隨機數。任何人都可以用web3.eth.getStorageAt()函數外部讀取私有變量randNonce(我們在上一期期已經闡述過詳細方法),而父塊哈希(blockhash(uint blockNumber))在合約內外都可以讀取到。這樣產生隨機數的計算方法就已經被看破,投機者只需在計算出較理想的隨機數時加入遊戲即可獲得空投。

除此之外,國外已有專業人士Arseny Reutov分析了3649份智能合約,發現有43份存在類似的可被利用的漏洞,並將此類情況稱為假隨機數生成漏洞(PRNG)。

如此看來,將區塊參數與熵聯繫起來運用到遊戲設計(尤其是博弈類遊戲)並不是個例。需要思考的是,以太坊的區塊參數能不能可靠的運用於熵。

以太坊沒有提供類似於傳統編程語言的rand()函數。於是實現去中心化的熵已經成為一個頗具規模的問題,許多人參與了這個問題的考究,甚至連V神自己也發表了一片文檔提出了一些完善計劃,例如使用RanDAO或者私有隨機(private randomness)。

所以,區塊參數能夠可靠的用於設計鎖倉功能,但是放在隨機數生成設計當中,它的地位相當不可靠,形象的來說,同樣的橘樹,生長在淮南長出甜的橘,生長在淮北長出苦的枳。

合約之熵,安全之殤——區塊參數依賴


區塊參數依賴漏洞返例

一、時間戳依賴

數據塊時間戳(block.timestamp)歷來被用於各種應用,例如隨機數的函數,鎖定一段時間的資金以及時間相關的各種狀態變化的條件語句。礦工有能力稍微調整時間戳,如果在智能合約中使用錯誤的塊時間戳,這可能會證明是相當危險的。

block.timestamp或者別名now可以由礦工操縱,如果他們有這樣做的動機。

例如下面這個簡單的遊戲合約:

合約之熵,安全之殤——區塊參數依賴


的假設是,block.timestamp關於最後兩位數字是均勻分佈的。如果是這樣,那麼將有1/15的機會贏得這個彩票。但是,正如我們所知,礦工可以根據需要調整時間戳。

在這種特殊情況下,如果合約中有足夠的ether,解決某個區塊的礦工將被激勵選擇一個block.timestamp % 15 == 0或now % 15 == 0的時間戳。在這樣做的時候,他們可能會贏得這個合約以及塊獎勵。由於每個區塊只允許一個人下注,所以這也容易受到前置交易攻擊。

在實踐中,塊時間戳是單調遞增的,所以礦工不能選擇任意塊時間戳(它們必須大於其前輩)。但是它們也限制在將來設置不太遠的塊時間,因為這些塊可能會被網絡拒絕(節點不會驗證其時間戳在未來的塊)。

二、區塊哈希依賴

在一些賭博遊戲合約中,使用區塊頭相關的參數來產生隨機數:區塊號(block.number)、區塊時間戳(block.timestamp)、區塊難度(block.difficulty)、區塊gas限制(block.gaslimit)等。當以太坊上礦工挖出一個區塊時,此時區塊頭的相關參數就可以被礦工獲知,一些惡意挖礦的礦工可以利用這些區塊參數進行攻擊。

例如下面這個遊戲合約

合約之熵,安全之殤——區塊參數依賴


一個實現輪盤賭博的智能合約中,其邏輯是如果下一個塊哈希值以偶數結尾,則返回一個黑色數字。一個礦工(或礦池)可以在黑色上下注100萬美元。如果他們挖出下一個區塊並發現區塊哈希值以奇數結尾,他們會丟棄該塊、繼續挖礦、直到他們挖出一個塊哈希值為偶數的塊,從而從漏洞合約中獲利。

漏洞修復

隨機數生成的方法有很多,並不一定要依賴區塊參數,下面介紹兩種理念防範礦工或者投機者。

隨機數的來源儘量來自於區塊鏈之外,這可以在具有諸如commit-reveal之類的系統的對等體之間完成。

通過將信任模型改變為一組參與者(例如在RandDAO)來完成。這也可以通過中心化的實體來完成,該實體充當隨機預言。

根據Solidity官方建議,合約開發者可以使用鏈外的第三方服務,比如Oraclize來獲取隨機數。

總的來說,塊變量(一般來說,有一些例外)不應該用於隨機種子,因為它們可以被礦工操縱。

問渠哪得清如許?為有源頭活水來

這些漏洞,類似事件,慘烈教訓,對區塊鏈產業進入寒冬負有不可推卸的責任,從技術角度不斷加強對於新知識的正確理解與使用,提高智能合約的安全性是讓這個產業冰消雪融,讓項目方、參與方合力破冰前行的唯一希望。望各位學而思之、思而踐之、踐而悟之。

合約之熵,安全之殤——區塊參數依賴



分享到:


相關文章: