以太坊合約的安全性弱點,你都繞開了嗎 III

新年前,咱們最後來談一談以太坊安全性的特色。

不可能修改的bug

當合約公開在區塊鏈上以後,它就不能去修改了。相應的,合約中出現的任何 bug 也沒有機會改正。若是但願可以修改bug,合約編寫者就須要在編寫合約的時候預留一些用來修改或終止合約的代碼。但預留修改後門這一方式具備爭議,由於在以太坊的願景中,智能合約一旦部署,其設定就應當是不可更改的。
正式由於 bug 不可修改,可能會致使一些很嚴重的攻擊事件沒有彌補的方法。DAO 攻擊是惟一的例外。以太坊使用了一個硬分叉解決了這一問題。但這種作法沒有獲得整個社區的贊同,由於它違背了「代碼即法則」這一準則。數組

調用棧大小限制

每次合約調用另外一個合約的時候,調用棧就會增長一個 frame. 上限是 1024 個。當這一上限達到的時候,下一次調用會觸發一個異常。若是攻擊者先將本身的調用棧離填滿只差一個 frame,而後去調用受害者合約的函數,那麼受害者函數執行中任何調用將會致使執行失敗。若是受害者函數沒有正確的處理執行成功與否,將可能致使意料以外的結果。在文章後續部分,咱們將以一個例子說明這一點。
爲了解決這一問題,在一次以太坊升級中,規定了每次經過 call 或 delegatecall 調用合約函數時,只能爲被調用函數分配最多 63/64 的剩餘 gas. 而以太坊中每一個區塊最多隻能包含約 470 萬的 gas。也就是說,若是調用者最初投入了數量爲 a 的 gas, 在 10 層遞歸調用後,最內層的函數最多隻有 (63/64)^10*a 的 gas. 所以,調用深度不可能超過 1024. 後面的攻擊案例中,假設尚未這一修補方案。安全

時間約束

大量的應用使用時間約束來決定某些行爲何時候被容許。好比在一個 ERC 20 合約中,從某個時刻開始,容許用戶使用 ether 購買一個 token.
在智能合約的執行過程當中,當前時間取自給定交易所在區塊的區塊時間戳。因此,一個區塊中的全部交易在執行時使用的是相同的時間戳。這一設定保證了智能合約在每一個礦工那裏的執行結果是一致的。
但這個設定也可能致使一些攻擊,由於礦工在選擇時間戳的時候有必定的自主權,這可能爲一些攻擊埋下了後門。微信

GovernMental 合約的攻擊

GovernMental 是一個「龐氏騙局遊戲」型合約。嚴格來講,其實不能叫騙啦,由於龐氏騙局的規則被公開地寫在合約裏。在這個合約中,每一個人經過向合約中轉一筆錢來加入這個龐氏騙局遊戲。合約經過兩個數組記錄參與者的地址和每一個參與者轉入的錢的數量。若是最後一我的加入後 12 小時後都沒有下一我的加入,那麼最後一我的就能夠得到所有的收益。(這個設定是否是有點像著名的 Fomo3D,值得注意的是,Fomo3D 的出現晚於這篇論文呦。)
下面是一個簡化版的 GovernMental 合約ide

clipboard.png

在這個合約中,參與者能夠經過 invest() 函數來投入 ether 並加入這個遊戲。合約維護一個名爲 jackpot的變量,表示若是後續沒有人加入,贏家將拿走多少 ether. 新來的參與者必須投入多於 jackpot 一半的 ether, 同時,新來的參與者投入的 ether 中,會有一半被加入 jackpot. 若是連續一分鐘沒有人新來的參與者,最後一我的得到 jackpot 中的 ether,同時合約擁有者拿走剩下的錢(留下 1 個 ether 做爲下一輪的啓動資金)。須要注意的是,這裏並無檢查最後分錢的時候,經過 send() 函數進行的轉帳是否成功。
這個簡化版的合約有幾個點可供被攻擊。函數

攻擊一

這個攻擊來自合約擁有者自身,目的是讓原本的遊戲贏家沒法拿到錢。合約擁有者利用 send() 函數的異常處理和調用棧大小限制進行攻擊。
攻擊的方式是,經過預先進行大量的遞歸調用,致使執行 resetInvestment() 時,調用棧達到了大小上限,沒法再執行給遊戲贏家和合約擁有者的 send() 函數。合約擁有者和遊戲贏家都拿不到錢,錢依然留在合約中,但以後重置合約狀態的代碼會照常執行。只要再進行一輪正常的遊戲,合約擁有者就能夠將本該屬於上一輪遊戲贏家的錢收入囊中。性能

攻擊二

這一攻擊方式來自礦工。礦工能夠經過拒絕打包其餘人與 GovernMental 合約的交易,來使本身但願的人成爲合約遊戲的贏家。更多地,進行攻擊的礦工在打包區塊時能夠任意決定交易順序,來影響這個區塊事後誰是 lastInvestor.
以前也提到過,每個新參與者須要投入的 ether 數量不能低於合約中 jackpot 中 ether 數量的一半。而一我的在發起交易的時候看到的 jackpot 數值,與它的交易被執行時 jackpot 的數值多是不同的。這就致使這我的可能發起交易時覺得本身投入的 ether 數量是符合要求的。可是執行時,因爲 jackpot 數值的改變,變成了一筆無效交易。這就是上篇文章中提過的不可預測狀態問題。
另外,礦工擁有決定區塊時間戳的權利。而合約在執行時,斷定 resetInvestment 是否能夠執行,就是讀取礦工決定的區塊時間戳。經過影響區塊時間戳,也能夠影響遊戲結果。學習

結語

經過這幾期對參考文獻 [1] 的學習,咱們看到了一些以太坊 Solidity 合約中設計的弱點。雖然這些弱點稱不上是漏洞,可是若是在編寫合約時,對這些點不瞭解,沒有充分考慮,就可能寫出有安全問題的合約出來。
參考文獻:
[1] Atzei, Nicola, Massimo Bartoletti, and Tiziana Cimoli. "A survey of attacks on ethereum smart contracts (sok)." Principles of Security and Trust. Springer, Berlin, Heidelberg, 2017. 164-186.區塊鏈

--
Conflux 是致力於打造下一代高性能的 DAPP 公鏈平臺
歡迎關注咱們的微信公衆號:Conflux中文社區(Conflux-Chain)
添加微信羣管理員 Confluxgroup 回覆「加羣」加入 Conflux官方交流羣spa

clipboard.png

相關文章
相關標籤/搜索