智能合約已知漏洞和陷阱

[ 轉自 ]基于區塊鏈的智能合約安全(二)——已知的漏洞和陷阱
博客新地址

私鑰泄露

使用不安全的私鑰確實是一個常見的用戶錯誤案例,甚至比漏洞還要常見。然而,我們也需要提這一點,因為它經常發生,而且某些玩家專門利用它從不安全的地址偷資金。

最常見的情況是在產品中使用生成地址(例如用在測試工具中的,如Ganache /TestPRC)。這些地址是由公眾所知的私鑰生成的。一些用戶甚至在不知不覺中將這些密鑰導入錢包軟件,通過原始種子生成秘鑰。

攻擊者檢測這些地址,任何轉移到這個在以太幣網絡主地址的金錢都會立即消失

一個有趣的文章研究了這項非常有利可圖的“清掃”活動,并且發現一個清掃人員賬戶已經設法積累了2300萬美元的資金。

可重入性和競爭條件

如果一個功能模塊在完成前調用了很多次,可能會出現意想不到的行為,在某些意想不到的行為中可能存在可重入性漏洞。

讓我們來看看下面這個函數,這個函數可用于從一個合約中取回訪問者的總余額。

這就相當于是DAO攻擊的原理了

call.value()函數可以導致合約外部的代碼執行。我們可以把調用者假設成一個數字加密貨幣錢包軟件,也可能是其它合同。

如果這個訪問者是另一個合約,這就意味著這個合約的回退函數被執行了。回退函數的目的就是收到資金。

一個流氓合約,實現一個叫做payout()的回調函數,在余額設置為0之前,再次遞歸調用payOut(),從而獲得比現有余額更多的資金。

這個問題的解決方案是使用可代替的函數sent()或者transfer()。通過為基本核算支付足量的gas,任何再次調用payout()的嘗試都將會失敗,從而可以防止遞歸調用。另外(或者是再者),操作的順序可能被翻轉,例如在金錢交易之前把余額設為0。

在第一部分中提及的DAO攻擊就用到這個漏洞的一個變種。

下溢/上溢

余額通常由無符號整數表示,Solidity中通常有256比特數字。當無符號整數下溢或上溢時,它們的值立馬就改變了。現在我們來看一個常見的下溢的例子(數字為了可讀性縮短了):

?0×0003
— 0×0004
———————-
?0xFFFF

這里很容易就會發現一個問題,減去一個比余額還要大1的數會導致下溢,結果余額會得到一個大數。

也請注意,由于舍入誤差,整數計算的除法會非常復雜。

解決方法是總是檢查代碼中的下溢或上溢。這里有安全庫協助檢查,例如SafeMath或者OpenZeepelin。

交易定單假設

(這我沒看懂)
交易進入未經證實的交易池并按照某種規律存在于礦工的數據塊中,這種規律取決于礦工的交易選擇標準,這很可能是一些試圖從交易手續費中獲取利益最大化的算法,但是也可以是其他的東西。

因此,打包交易的順序和它的生成順序完全不同。為此,合約代碼不能在交易規則里創造任何假設。

由于交易是可見的,而且這個交易是可以預見的,所以除了執行合約過程中沒有預料到的結果,這里還可能有一個攻擊向量,這可能是交易中的一個問題,也就是延遲交易可能會被流氓礦工用于個人利益。事實上,在交易之前就需要意識到某些的交易,既可以被礦工利用,也可以被其他的任何人利用。通過支付一個較高的gas,鼓勵礦工迅速將其打包,最終交易可以被“overtaken”。

時間戳依賴性

在區塊鏈中,時間戳是由礦工生成的。因此,合約不需要為了核心操作依賴于數據塊的時間戳,例如把它用作生成隨機數的種子。Consensys在他們的指南中給出一個12分鐘法則,該規則規定,如果你的時間依賴代碼能夠處理12分鐘時間變化,那么使用block.timestamp是安全的。

總結

到今天為止,我們看了很多獲得了高關注度的基于區塊鏈的智能合約攻擊的例子,我們也討論了一些已經發現的常見的漏洞。在下一篇文章中,我們將會介紹一些更復雜的攻擊,這些攻擊依賴于區塊鏈和特定操作的工作方式。

*參考來源:security of blockchain-based smart contracts II-Konwn Vulnerabilities and Pitfalls,本文由丁牛網安實驗室小編EVA編輯整理,如需轉載請標明出處。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容