您好,登錄后才能下訂單哦!
最近以太坊也算是問題不斷,多個游戲都相繼被爆出了黑客攻擊,首當其沖的當然還是最近比較火爆的類Fomo3d的游戲,比如last winner所遭遇的薅羊毛的攻擊,雖然相關的攻擊手法早在一個月前就已經有 相關的披露 ,但是last winner并沒有開源,似乎也沒有采取什么安全措施,加上黑客的手法也進行了升級,導致了大量的eth被黑客通過空投的方式拿走,不過這并不是今天的重點,這部分可以看看相關的 解析
另外一個比較勁爆的消息當然就是fomo3d首輪的結束,獲勝者成功奪得了高達一萬eth的獎金,而背后的黑客所使用的手法正是阻塞以太坊網絡,不讓fomo3d相關的交易能夠被打包進區塊,于是作為最后的購買人的他便成功將巨額的獎金收入囊中,可以說是利用對以太坊網絡的DDOS完成了這次攻擊,在這里我們就來簡單談談以太坊中的DDOS
其實說來也有趣,本身以太坊設計的時候就想過要抗衡DDOS的,其中的gas機制有一部分作用也是為了防止DDOS,抬高DDOS所需的成本,不過隨著以太坊的不斷發展現在也暴露出越來越多的問題
這個問題差不多是兩年前提出來的,主要存在的問題還是在EXTCODESIZE這個操作碼上,熟悉智能合約的人應該也知道這是用來讀取合約的code的大小的,所以其涉及到了相應的磁盤操作,但是它所需的gas又非常少,這就導致了惡意的攻擊者可以在交易里實現調用很多次這個操作碼,只要這些操作的gas加起來不超過區塊的gas limit即可,得益于此操作碼的極少gas消耗,當時的攻擊交易在每個區塊調用了該操作碼近50000次,因此這一個區塊內的交易所占用的計算時間就被大大延長,從而導致了整個以太坊網絡的癱瘓,在以太坊官方博客上也有對應的 說明 和相應的 處理
說到這里我們還是不得不提一下以太坊特色的gas機制,對于它的存在目前確實也是褒貶不一,我也不作過多的評價,我們主要來關注一下要注意的問題
我們知道只要發送交易就必定會產生gas費用,而我們在發送一個交易時其實也有兩個關于gas可選項,即gas Price和gas limit,gas Price即我們愿意為每個gas所支付的單價,而gas limit則為我們設定的gas的最多用量,也即我們直接發送過去的gas數量,然后在節點處打包后計算出了該交易中的操作所消耗的gas數,即gas used,然后gas used*gas Price就是我們實際支付的tx fee的數目,剩余的gas則將返還給我們的賬戶,如果設定的gas limit還不夠操作所需gas的話該交易就失敗了,對應的操作也將回滾,但是交易仍然會打包進區塊,當然已經給了的那部分gas就別想了
所以有時候我們碰到發送的交易失敗可能就是設定的gas limit少了點,你可能會覺得直接都把gas limit設置的特別大不就什么事也沒有了,但是這樣的做法可能并不會得到礦工的好感,因為以太坊還有一個特點就是它的區塊gas limit,不同于比特幣是直接限定區塊的大小,以太坊是通過區塊內交易所使用的gas來對區塊進行限制,對應的限制值就是區塊gas limit,礦工在選擇要打包進區塊的交易時必須保證所有交易使用的gas值要小于區塊的gas limit,所以一個區塊內所能容納的交易數目還是比較有限的,同時一般的交易的gas limit在21000左右,因為這也是很多客戶端默認的gas limit,當出現一個gas limit特別大的交易時礦工可能并不會給與其優先權,因為可能打包了這個交易后實際發現它實際所使用的gas也將那么點,大部分都返還回去了,這樣它倒不如多打包幾個gas limit較小的交易,能賺取的gas可能更多,所以說較高的gas limit反而可能導致你的交易的效率變低,如果真的希望交易能較快地打包進區塊,應該提升的值還是gas price,這樣最終礦工所得到的tx fee才會變高,也就相應的能取得優先權
那么回到這個垃圾交易的DDOS攻擊上來,官方的緩解方案其實也是跟區塊的gas limit有關,一方面是增加對應的操作碼所需的gas,另一方面則是減小區塊gas limit的大小
我們可以來看看當時區塊gas limit的變化
本來區塊的gas limit是在470萬左右,之后為了緩解攻擊下調到了150萬左右,然后又調整到200萬,這其實也很好理解,目的就是為了減少每個區塊內的交易數目,避免出現一個區塊在計算交易的過程中出現阻塞幾十秒的情況,雖然說這么做也還是治標不治本,不過也是為以太坊對該漏洞的修補爭取緩沖時間,其實本身區塊的gas limit也是有動態的調節機制的,它也是在根據前面的區塊的gas used進行上下波動,不過在這種局面下它還是失去了調節的能力,之后隨著以太坊又進行分叉來對漏洞進行了修補,區塊的gas limit又開始了不斷的增長,一直到目前的800萬,當然,太高的話也還是會影響性能,因為這樣每個區塊里的交易數就變多了,現在的800萬的gas limit也已經穩定了很久了
雖然現在這種DDOS方式已經被修復,不過還是值得拿出來說道說道
其實嚴格說來這種可能也談不上DDOS攻擊,這就相當于雙十一的時候淘寶也爆卡一個道理,不過它也確實造成了以太坊的堵塞,這種情況在最近一年來倒也變得愈發頻繁
我們不妨先來看看近一年來gas Price的變動
其實平均設置的gas Price就在一定程度上反應了以太坊的堵塞程度,因為當等待的交易過多時想讓自己的交易被礦工優先選中就必須提高gas的價格,否則你的交易可能就一直在交易池里躺著了,這樣就導致了以太坊堵塞時gas Price的飆漲
從圖中我們可以大致看出幾個上漲點,首先就是17年末到18年初的階段,有印象的話應該記得那時候正是以太貓流行的時候,當時它名氣那么大也正是因為它的存在一度堵塞了整個以太坊網絡,數不清的交易躺在交易池里打包不了,帶來的也是gas Price的飆漲,大家都在游戲里搶貓,在上線不到兩周的時間里便交易了七萬只,交易額達到了七千多萬,讓人不禁感嘆資本的力量,那應該也是以太坊首次出現一個如此流行的游戲,當時也算是最接近于殺手級的應用了,意義也還是很重大的
之后有一個比較明顯的漲幅就是來自于不久前也就是七月份爆火的FCoin交易所,因為其特殊的排名模式,也就是對對應的代幣采用一賬戶一票的方式進行排名,導致了對應的項目方瘋狂地開賬戶并進行投票,這就造成了大量的交易,直接堵塞了整個以太坊網絡,這樣的行為也受到了多方的譴責,畢竟這樣的行為除了擴大了其影響力并沒有任何意義,還造成了gas Price的居高不下,偏偏對于這樣的無賴方式還沒有辦法反抗,這次的事件也再次對以太坊的性能問題敲響了警鐘,畢竟它確實是很容易引發大面積的堵塞,可以想象以太坊的網絡帶寬也就是每15秒800萬gas左右,還有計算性能的限制,v神也在不斷尋求解決方案,其設想的分片技術也是為了提升以太坊性能來減少擁堵情況的發生,不過卻是會犧牲部分去中心化的特性,這倒是有點類似于EOS
最后,離我們最近的一個峰值表示的就是最近仍然火爆的類Fomo3d游戲了,影響到甚至阻塞網絡的正是風頭正勁的last winner游戲,在開始時他們團隊還準備了2大量eth進行刷單,強行抬高了交易量,吸引用戶注資,當時其交易數據甚至夸張到3天吸金近1億,這在當時的市場環境下確實是過于夸張,也一度造成了以太坊網絡的擁堵,而且在這場游戲的背后也是疑云重重,從其營銷策略來看應該還是針對國人的,只能說對待這樣的游戲必須得多加小心
關于gas Price的實時情況我們可以在 這里 觀察到,而其在最近一段時間的變動情況也可以在 此處 得到很好的分析
這種類型的DDOS涉及的就是前幾天爆出的Fomo3d的獲勝黑客所使用的攻擊手法了,這名黑客使用這種手法阻斷了以太坊網絡近三分鐘,使得與fomo3d相關的交易都無法打包進區塊,于是作為最后一個購買者的他便成為了最終的獲勝者,獲取了巨額的獎金
這里涉及到的還是我們前面提到的區塊的gas limit的限制,目前每個區塊的gas limit是800萬左右,攻擊者要做的就是想辦法讓自己的交易耗盡區塊的gas limit,努力讓區塊內盡量只存在自己的交易,這部分的優先權可以通過提高gas Price取得,而對于gas的消耗則涉及到另一個操作,也就是對assert的應用
熟悉智能合約相關操作的人應該也都知道assert與require類似,都可以用來進行錯誤的處理,不同之處在于require觸發使用的是0xfd操作碼,也就相當與調用了revert,它會回退合約狀態并返還剩下的未消耗完的gas,而assert則霸道得多,觸發過后并不會返還剩下的沒消耗的gas,你只能當貢獻給礦工了,你可能會奇怪既然如此為何還要使用assert,實際上主要還是在于使用的場景不同,對于require的應用場景來說,哪怕其觸發了,表示的其實也是正常的合約狀態,因為其一般是檢查用戶的輸入抑或是執行的狀態條件,而assert的觸發場景則一般代表著代碼可能存在某些問題,你可以把這理解為一個規范,遵循這樣的規范的代碼就可以畢竟容易的使用分析工具進行檢查,關于二者更詳細的分析比較可以參加此處的 資料
對于這一特性,我們可以簡單地來看看效果
部署一個簡單的測試合約
contract C{ function requires(){ require(false); } function asserts(){ assert(false); } }
我們將其部署到ropsten測試鏈上,因為測試鏈的區塊gas limit在470萬左右,我們設置一下發送交易的gas limit,對于調用asserts的交易,我們直接將其gas limit設置為465萬,至于調用requires的交易我們使用300萬即可,然后我們來看看結果
對比很明顯,調用asserts的交易直接耗光了我們設置的gas limit,而requires僅使用了所需的gas,我們再看看asserts所在交易的區塊情況
果然,這個區塊僅有兩個交易被打包,我們再看requires所在區塊
可以看到該區塊打包了一百多個交易,那么至少我們是阻塞了asserts所在的區塊了,不過事實上這種單個巨額gas limit的堵塞效果并不是很好,如果你也進行嘗試的話應該能注意到這個交易也是等待了一段時間才被打包,比require那個交易要慢很多,要知道我設置的gas Price已經很大了,其實原因前面也提到了,這種單個的超高gas limit的交易礦工并不是很待見,所以比較好的辦法其實是將其拆分為幾份,攻擊fomo3d的那位黑客也明白這一點,所以他的攻擊的交易大都集中在兩三百萬gas limit左右
這是當時黑客攻擊時所產生的某個區塊,可以看到該區塊的交易數量僅為10個,而正常區塊下一個區塊的交易數目是有好幾百的,其中顯示失敗的那三個交易其實就是黑客發出的交易,目標都是一致的,也就是黑客部署的攻擊合約,其實這目的也就是利用assert消耗gas
我們來看看這幾個交易分別消耗了多少gas
很有意思,分別是20萬,330萬和420萬,加起來就是770萬,頂去了整個區塊gas使用量的絕大部分,在整個攻擊過程中黑客其實也在不斷調整,修改gas使用量,其實前面也經歷了很多的失敗,不過在最后這三分鐘他還是取得了成功,可能還是有一點運氣的成分吧,這整個調整的過程也挺值得深入研究的,至于這次攻擊手法的詳細解讀可以參見此處的 分析
隨著這種攻擊方式的成功應用,很多黑客團體也著手展開了對類fomo3d游戲的攻擊,目前也已經有了不少成功的例子,不久前last winner 第二輪也宣告結束,這是否又意味著這類游戲的新的篇章,在這種形勢下確實是很難說清了
這里要說的就不是ddos攻擊了,關于這部分內容我感覺真正談得上可攻擊可利用的還是對于區塊gas limit的限制利用,因為區塊得gas的800萬限制,如果想辦法讓合約的部分操作的調用所需的gas超出了800萬的限制,那么這個合約自然就廢了
比如下面這個合約的主體部分
contract DistributeTokens { address public owner; // gets set somewhere address[] investors; // array of investors uint[] investorTokens; // the amount of tokens each investor gets function invest() public payable { investors.push(msg.sender); investorTokens.push(msg.value * 5); } function distribute() public { require(msg.sender == owner); for(uint i = 0; i < investors.length; i++) { transferToken(investors[i],investorTokens[i]); } } }
攻擊者就可以通過創建大量的investor來使得最終調用distribute函數時所需的gas超過了區塊的gas limit,從而使得這個合約作廢,當然這也只算是使智能合約無法提供服務的方法中的一種,其他的利用可見此處的 資料
最近以太坊所出現的一系列問題還是讓人非常擔憂,所涉及的金額也越來越大,這樣其實是侵犯了很多普通用戶的權益的,希望在后面以太坊團隊能解決以太坊目前存在的性能問題,避免擁堵的再次發生
本文轉載自“安全客”
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。