本文轉載自微信公號「萬向區塊鏈」,爲慢霧安全負責人海賊王在萬向區塊鏈實驗室舉辦的2018上海區塊鏈國際周-技術開放日上的演講速記整理。程序員
這張圖總結了智能合約攻防的各個方面,分爲兩大部分:鏈上攻防和鏈下攻防。後端
鏈上攻防瀏覽器
對於鏈上攻防,選取5個方面進行詳細剖析。「Talk is cheap. Show me the code.」 下面開始展現源碼詳細解讀。安全
一、溢出微信
由於沒有使用 SaceMath致使的溢出形成金額能夠在攻擊者構造的數據中被任意控制,從而致使條件判斷成立最終攻擊者成功攻擊了該智能合約。網絡
此類問題避免方法:在作數字計算的相關代碼處嚴格使用 SafeMath 進行作算術運算,防止溢出產生。併發
二、權限控制app
此類權限控制屬於權限問題中的一種,因爲合約開發人員的不專業致使的代理轉帳函數中未進行受權判斷,從而致使任何人均可以轉走別人的錢。函數
此類問題避免方法:找專業的開發人員進行合約開發,同時合約開發人員也須要及時提升本身的開發技能以及專業能力,因爲區塊鏈的去中心和Token的特殊性很容易由於一個小的漏洞致使項目方今後身敗名裂,因此建議項目上線以前找專業的安全審計團隊出職業的審計報告,此類問題慢霧在審計的過程當中必定可以發現並幫助項目方避免這種尷尬的狀況。區塊鏈
三、條件競爭
此類問題爲條件競爭致使的跨合約調用屢次惡意轉帳最終攻擊者成功完成攻擊,在跨合約調用方面一直存在很大的問題,因爲開發者的專業技能不夠專業或者是合約設計的不合理等問題都會致使此類條件競爭。
此類問題避免方法:瞭解 Solidity 語言自己的函數使用場景以及底層實現,而且在業務邏輯上先扣除須要減去的帳戶金額再添加到對應帳戶並及時清零中間變量的臨時值,避免由於事務的問題致使多入帳致使損失,同時也要了解清楚Solidity中someAddress.call.value()方法 和 someAddress.transfer() 方法還有someAddress.send() 方法的區別。很是不建議使用 someAddress.call.value(),具體緣由請你們必定要本身動手去查一下。
四、假充值
假充值這類問題是一個系列,好比XRP的假充值和USDT的假充值等,在這裏只講 ERC20 的假充值問題,這種問題是因爲合約開發人員的邏輯判斷代碼不規範致使在以太坊的區塊瀏覽器中能夠看到本來一筆失敗的轉帳狀態爲Success交易所在進行充值入帳的時候也沒有嚴格進行狀態的判斷和金額的校驗從而致使了此類問題,此類問題殺傷力強,而且一次足以讓一個交易所虧損上百萬及千萬,不管是開發者仍是交易所都須要足夠重視假充值的問題。
此類問題避免方法:合約開發中代碼判斷邏輯的地方使用 require()或者 assert()進行判斷,若是條件不知足會直接致使 transfer 的失敗同時狀態也是 fail ,交易所錢包業務開發人員須要在充值的時候注意嚴格校驗轉帳狀態是成功仍是失敗,同時對充值金額也進行校驗,確認真的到帳後此筆交易纔算成功。
五、惡意事件
此處須要說明這裏的代碼僅僅是咱們編寫做爲演示使用的,目前暫時沒有發現這種真是的攻擊行爲。因爲區塊鏈的數據都記錄在鏈上,惡意記錄 event 的事件能夠直接修改對應的參數,若是此代碼真是存在則上面講的假充值就真的成了真充值了。
此類問題避免方法:作好 Code Review 和找專業的代碼審計。
鏈下攻防
對於鏈下攻防,一樣從5個方面詳細剖析。
一、WEB
在以前發生的MyEtherWallet發生的域名劫持事件前,實際上相關的安全機構已經給出了中級風險的提示(以下圖),可是它並無對此重視。
專題介紹:https://mp.weixin.qq.com/s/-Yiul1QtSNa9JJAOuXCx3A
二、終端
對於硬件錢包的安全,也可能存在各類的安全隱患如:是否使用加密芯片,工業設計是否安全,作工是否很簡陋不考慮丟失以及意外破損和可否以應對低溫高溫的狀況下正常使用,最終須要考慮你究竟是買了個硬件仍是真正的硬件錢包?
三、節點
好比以太坊黑色情人節事件,攻擊者經過在網絡上經過 P2P協議發現新的以太坊全節點,而後構造好攻擊腳本作好工程化等待時機對新搭建的全節點進行攻擊,因爲不少小白用戶不懂得如何防護此類攻擊因此到目前位置仍是有不少團隊不斷被盜ETH。
詳見慢霧的專題頁:https://4294967296.io/eth214/
專題介紹:https://mp.weixin.qq.com/s/-Yiul1QtSNa9JJAOuXCx3A
慢霧的防護方法:https://mp.weixin.qq.com/s/Kk2lsoQ1679Gda56Ec-zJg
四、礦工
礦工有可能做惡,針對Dapp,進行選擇性的打包。針對礦池,針對塊代扣攻擊等。
五、後端
後端的攻擊舉例爲,USDT 假充值。
攻擊步驟爲:
1)向交易所錢包構造併發起⽆效(虛假)轉帳交易;
2)因爲邏輯判斷缺陷交易所將⽆效交易⼊帳並計⼊到⽤戶在交易所的資⾦帳戶;
3)⽤戶發起提幣;
4)交易所處理⽤戶提幣將幣打到⽤戶⾃⼰錢包地址;⽤戶⾃⼰充幣環節USDT 沒有任何損失,提幣環節交易所把⾃⼰真實的 USDT 幣打給⽤戶,形成交易所損失。
這背後的原理是:
USDT 是基於 Bitcoin 區塊的 OMNI 協議資產類型,利⽤ Bitcoin 的 OP_RETURN 承載相關交易數據;
Bitcoin 本⾝並不會校驗 OP_RETURN 數據的「合法性」,能夠是任意數據;
Bitcoin 交易當區塊確認數達到 6 的時候,就會被Bitcoin 節點認可;
那麼,USDT 的交易在 OMNI 的節點上如何被確認的呢?
int64_t nBalance =
getMPbalance(sender,property, BALANCE);
說明:經過上⾯的代碼來看,OMNI內部有⾃⼰的⼀套基於地址的記帳模型,經過地址能夠獲取地址的餘額。
所以,爲了不以上問題。⼀筆 USDT 的交易合法的,要⾄少滿⾜如下兩個條件:
(1)要經過⽐特幣的交易來構造,要符合⽐特幣的餘額驗證(BTC)及交易規則驗證
(2)要經過 USDT ⾃⼰的餘額(USDT)驗證
對於USDT 假充值,當餘額不足時會發生什麼?
{"amount": "28.59995822",
"block": 502358,
"blockhash": "0000000000000000005968fa48c49d7c4fb2363369d59db82897853fd937c71a",
"blocktime": 1514985094,
"confirmations": 37854,
"divisible": true,
"fee": "0.00200000",
"flags": null,
"invalidreason": "Sender has insufficient balance",
"ismine": false,
"positioninblock": 301,
"propertyid": 31,
"propertyname": "TetherUS",
"referenceaddress": "1Po1oWkD2LmodfkBYiAktwh76vkF93LKnh",
"sendingaddress": "18DmsHjHU6YM2ckFzub4pBneD8QXCXRTLR",
"txid": "1b5c80f487d2bf8b69e1bbba2b1979aacb1aca7a094c00bcb9abd85f9af738ea",
"type": "Simple Send",
"type_int": 0,
"valid": false,
"version": 0 }
另外,有些黑客很是有心機,在一些百度回答等貼上錯誤的代碼,若是程序員不仔細檢查或者對智能合約不熟悉,直接複製粘貼代碼,則容易遭受攻擊。要如何提高安全呢?首先開發人員擁有安全開發意識,其次仍是要找專業的安全團隊作專業的審計。