本教程適用于所有希望向主網推出user-ready應用程序的人員
如果你想要將構建的DeFi協議或是其他智能合約應用發布到區塊鏈主網上,安全因素一定是你要首先去考慮的。
許多團隊在審查代碼時只關注Solidity方面的問題,但要確保一個DApp的安全性并使其適配主網,還有很多其他問題需要關注。
了解近期高發的DeFi安全威脅——比如價格預言機攻擊、暴力破解攻擊以及其他攻擊手段,將保護你以及你的用戶數十億美元的資產。
因此啟動項目前做好盡職調查必不可少。
本文由CertiK及Chainlink聯合出品,將為你分享DeFi安全的10個最佳實踐,這將有助于防止你的應用程序成為攻擊的受害者。
?超長干貨,建議先收藏再看哦!
1.意識到重入攻擊的危害
以智能合約為中介進行的攻擊并不總是來自于外部。
重入攻擊作為臭名昭著DAO攻擊的一種形式,是DeFi安全中常見的攻擊類型。
當合約調用另一個惡意合約的外部函數時,該惡意合約可以通過fallback(回調函數)進行重入攻擊回調到原合約。
這是DeFi安全攻擊的一種常見類型——惡意合約可以在第一個函數完成前回調到調用合約之中。
引用Solidity文檔中對于重入攻擊的描述:"一個合約與另一個合約的任何互動,以及任何以太幣的轉移都會將控制權交給該合約。這使得合約有可能在這個互動完成之前回調到合約"。
我們來看一個例子?
Let’slookatanexample:```solidity//SPDX-License-Identifier:GPL-3
functionwithdrawBalance()public{??uintamountToWithdraw=userBalances;??msg
```
在一個函數執行完成之前調用其他函數
對開發者而言這是一個明顯的提醒——在ETH轉賬之前一定要先更新內部狀態。
一些協議甚至在其函數上添加互斥鎖,這樣如果函數尚未返回,該函數就不能被再次調用。
除了常見的重入漏洞,還有一些重入攻擊可以由特定的EIP機制觸發,如ERC777。
ERC-777是建立在ERC-20之上的以太坊代幣標準。
它向后兼容ERC-20,并增加了一個功能,使"操作員"能夠代表代幣所有者發送代幣。
關鍵是,該協議還允許為代幣所有者添加"send/receivehooks",以便在發送或接收交易時自動采取進一步行動。從UniswapimBTC黑客事件中可以看出,該漏洞實際上是由Uniswap交易所在余額更改之前發送ETH造成的。
數據:目前已有近5億枚DAI存入SavingsDAI:金色財經報道,據21co鏈上數據分析師Tom Wan披露數據顯示,在DAI將存款利率提升至8%后,存入SavingsDAI的DAI數量出現激增,目前已有4.86億枚DAI被存入sDAI,占到當前存款總量的41%。[2023/8/11 16:20:37]
在該攻擊中,Uniswap的功能設計沒有遵循已被廣泛采用的??"ChecksEffectInteractive"模式,該模式是為了保護智能合約免受重入攻擊而發明的,按照該模式,代幣轉移應該在任何價值轉移之前進行。
2.使用DEX或AMM中的代幣余額儲備作為代幣價格參考會產生漏洞
這既是用于攻擊協議的最常見方法之一,也是最容易防御的DeFi攻擊類型。
使用`getReserves()`來決定代幣價格是十分危險的。
當用戶通過使用閃電貸攻擊基于訂單簿或自動做市商(AMM)的去中心化交易所(DEX)中的代幣價格,這種中心化的價格預言機就有可能會被攻擊。
在被閃電貸攻擊時,因為項目使用了DEX中的價格作為他們的價格預言機的數據,導致智能合約的執行出現異常,其形式包括觸發虛假清算、發放過大的貸款或觸發不公平交易。
由于這個漏洞,即使是市面上主流的DEX——例如Uniswap,?也不建議單獨使用代幣對(swappair)中兩種代幣的相對比率作為價格預言機的定價。
在基于DEX或AMM的價格預言機中,預言機的數據源是DEX上一次成功交易,代幣對調整之后的代幣余額,即代幣對中兩種代幣的相對比率。
該價格可能與代幣的實際市場價格不同步。
例如,如果進行了大額交易時代幣對中沒有足夠的流動性來支持,將會導致代幣價格與交易所的平均市場價格相比發生較大波動,當用戶大量買入時代幣價格會飆升,當大量賣出時代幣價格會狂跌。
閃電貸加劇了這一問題,因為它允許所有用戶在沒有任何抵押的情況下獲得大量臨時資金,以執行大額交易。用戶經常將問題歸咎于閃電貸,稱之為“閃電貸攻擊”。
然而,根本問題是——他們自己的DEX使用的是不安全的價格預言機,代幣價格很容易被操縱,導致依賴預言機的協議引用了不準確的價格。
這些攻擊應被更準確地描述為“預言機操縱攻擊”,這一攻擊形式在DeFi生態系統中造成了大量的攻擊事件。因此所有開發人員都應該在智能合約中刪除可能導致價格預言機被操縱的相關代碼。
這里以最近一次攻擊的代碼舉例,此次攻擊造成了3000萬美元的損失,并使該協議的獎勵代幣的價格暴跌?。
```javascriptfunctionvalueOfAsset(addressasset,uintamount)publicviewoverridereturns(uintvalueInBNB,uintvalueInDAI){??if(keccak256(abi.encodePacked(IProtocolPair(asset).symbol()))==keccak256("Protocol-LP")){????(uintreserve0,uintreserve1,)=IPancakePair(asset).getReserves();??????valueInWETH=amount.mul(reserve0).mul(2).div(IProtocolPair(asset).totalSupply());??????valueInDAI=valueInWETH.mul(priceOfETH()).div(1e18);??}}```
Arbitrum網絡總鎖倉量達21.7億美元,GMX占比26.2%:金色財經報道,據DefiLlama數據顯示,Arbitrum網絡總鎖倉量達21.7億美元,較上月增長約0.82%。其中,GMX占比26.2%,較上月增長約14%。[2023/4/24 14:22:33]
該項目有一個預言機機制,可以從DEX中獲取代幣價格。
在DEX中,用戶可以將一對代幣存入流動性池合同,允許用戶根據匯率在這些代幣之間進行交換,匯率根據池中每一方的流動性數量計算。
現在有一個假設,如果一個項目大部分代碼是從熱門項目Uniswap中拷貝而來,我們可以認為這個項目是安全的。?
然而如果項目方在此基礎之上添加了一個獎勵代幣項目,當用戶向LP權益池中存儲流動性時,他們不僅可以獲得流動性代幣LPtoken,還可以獲取流動性挖礦的獎勵代幣。
這種情況下,黑客可以通過閃電貸將大量資金存入流動性池,從而操縱這個獎勵代幣的鑄造功能,這使得他們能夠以錯誤的比率兌換獎勵代幣。
在下方這個函數中,我們可以看到,攻擊者做的第一件事就是根據流動性池中兩種資產的儲備量,獲得流動性池中資產之間的匯率。
下面這行代碼的目的是獲得流動性池中的代幣儲備?
```javascript(uintreserve0,uintreserve1,)=IProtocolPair(asset).getReserves();```
如果一個流動性池中有5個WETH和10個DAI,那么它的reserve0為5,reserve1為10。
當你獲得了流動性池中每種代幣的儲備量之后,將兩個儲備量相除,得到的匯率就可以定義代幣對中任意一種資產的價格。
根據上面的例子,如果流動性池中有5個WETH和10個DAI,那么兌換率是1個WETH兌換2個DAI——用10除以5。
雖然使用去中心化交易所可以很好地交換具有即時流動性的資產,但這并不能保證DEX提供的價格比率是正確的,因為DEX中的價格很容易被閃電貸操縱,并且單個DEX中的交易數據往往只代表資產的總交易量的一小部分。
所以當其被用于計算獎勵代幣數量時,智能合約的執行很容易變得不準確。
以下面的代碼為例?
Slightlymodifiedforcomprehension```javascript//ProtocolMinterV2.sol0x819eea71d3f93bb604816f1797d4828c90219b5dfunctionmintReward(addressasset/*LPtoken*/,uint_withdrawalFee/*0*/,uint_performanceFee/*0.00015...*/,addressto/*attacker*/,uint)externalpayableoverrideonlyMinter{??uintfeeSum=_performanceFee.add(_withdrawalFee);??_transferAsset(asset,feeSum);//transfersLPtokensfromVaultFlipToFliptothis??uintprotocolETHAmount=_zapAssetsToProtoclETH(asset,feeSum,true);??if(protocolETHAmount==0)return;??IEIP20(PROTOCOL_ETH).safeTransfer(PROTOCOL_POOL,protocolETHAmount);??IStakingRewards(PROTOCOL_POOL).notifyRewardAmount(protocolETHAmount);??(uintvalueInETH,)=priceCalculator.valueOfAsset(PROTOCOL_ETH,protocolETHAmount);//returnsinflatedvalue??uintcontribution=valueInETH.mul(_performanceFee).div(feeSum);??uintmintReward=amountRewardToMint(contribution);??_mint(mintReward,to);//mintstherewardtotheliquidityprovidersandattacks}```
數據:近7600萬枚BUSD在Paxos財政部燒毀:金色財經報道,Whale Alert數據顯示,75,707,700枚BUSD(75,707,700美元)在Paxos財政部燒毀。[2022/12/25 22:05:55]
在這個例子中,向用戶進行獎勵代幣發放的主要函數是_mint(mintReward,to);。
我們可以看到,該函數根據用戶在流動性池上鎖定的資產價值來鑄造獎勵代幣。
因此,如果一個用戶突然在流動性池中擁有大量的資產,那么該用戶可以輕易地為自己鑄造大量獎勵代幣,這部分代幣是從其他用戶的獎勵中竊取的。
然而,目前的利潤水平依舊沒有達到攻擊者的期望。
因此,操縱DEX中代幣的價格可以大大提升他們竊取的代幣價值。
在這個例子中,合約認為他們給用戶發放了價值5美元的獎勵代幣,但實際上發放了5000美元。
通過這種設置,惡意用戶可以很容易地進行閃電貸攻擊,將獲取的臨時資金存入流動性池,鑄造大量的獎勵,然后償還閃電貸款,獲得的利潤由其他流動性提供者承擔,從中獲利。
為了防止基于閃電貸攻擊的價格操縱問題,通常的解決方案是采取DEX市場的時間加權平均價格。
雖然這可以防止閃電貸歪曲預言機價格,因為閃電貸只存在于一個交易或區塊中,而TWAP是多個區塊的平均值,但這并不是一個完整的解決方案,因為TWAP有其自身的妥協。
在價格劇烈波動時期,TWAP預言會變得不準確,這可能會導致下游事件——如無法在期限內清償抵押不足的貸款。
此外,TWAP預言沒有提供足夠的市場覆蓋率,因為它只追蹤一個DEX中的數據,使其它容易受到不同交易所的流動性或交易量變化的影響,從而影響TWAP預言給出的價格。
解決方案:使用去中心化的預言機網絡
與其使用中心化預言機來確定匯率,保證DeFi安全的最佳做法是使用去中心化的多個預言機組成的網絡來確定代幣的實際市場價格。
一個DEX作為一個交易所是去中心化的,但把它作為定價信息參考時它是中心化的。
正確的做法是:你需要收集所有流動性中心化和去中心化交易所的價格,按交易量加權,并去除偏差值/清洗交易,以獲得相關資產全球匯率的去中心化準確視圖,確保能反映市場的實際價格。
如果你能獲取基于所有交易環境的成交量加權的全球平均值的資產價格,那么閃電貸在單一交易所中操縱資產價格就不是問題。
此外,由于閃電貸款只存在于單個交易中,它們對去中心化的價格源并沒有影響,這些價格源在單獨的交易中產生具有能代表全球市場的實際價格更新。
Chainlink預言機網絡的去中心化結構及其實現的廣泛市場覆蓋,保護了DeFi協議免受閃電貸攻擊導致的價格操縱,這就是為什么越來越多的DeFi項目正在集成Chainlink價格反饋機制,以防止價格預言機被攻擊,并確保在突發的交易量變化中準確定價。
數據:Tornado Cash遭制裁后USDT和USDC出現市值翻轉,前者市值已增加近20億美元:8月16日消息,自美國財政部對加密貨幣混合器 Tornado Cash 實施制裁以來,Tether ( USDT ) 市值增加了近 20 億美元。加密 KOL TheLondonCrypto 在社交媒體發文表示,在 Tornado Cash 制裁之后,用戶將價值約 16 億美元的 USDC 轉移至 USDT。(Cointelegraph)[2022/8/16 12:29:15]
你不需要再使用`getReserves`來計算價格,而是從Chainlink數據源中獲得代幣交換比率,Chainlink數據源是去中心化的預言機節點網絡,在鏈上提供能反映所有相關CEX和DEX的資產加權平均價格。
```soliditypragmasolidity^0.6.7;import"??/**??*Returnsthelatestprice??*/??functiongetThePrice()publicviewreturns(int){????(??????uint80roundID,??????intprice,??????uintstartedAt,??????uinttimeStamp,??????uint80answeredInRound????)=priceFeed.latestRoundData();????returnprice;??}}```
上面的代碼是實現Chainlink價格預言機的全部內容,你可以通過閱讀文檔嘗試在應用程序中進行實現。
如果你剛開始接觸智能合約或預言機,我們有一個初學者教程,幫助你入門,并保護你的協議及用戶免受閃電貸和預言機操縱攻擊。
如果你想了解更多詳情,可以試試查看OpenZeppelin的DEX??Ethernaut,它顯示了操縱DEX的代幣價格有多么容易。
3.不要使用Keccak256或Blockhash生成隨機數
使用?"block.difficulty"、"block.timestamp"、"blockhash"或任何與區塊相關的參數來生成隨機數,都會使你的代碼被惡意攻擊。
智能合約中的隨機性在許多用例中都很有用,例如無偏見地確定獎品的獲得者,或者公平地將稀有NFT分配給用戶。
然而,區塊鏈是確定的系統,不提供隨機數的防篡改來源,所以在不查看區塊鏈外部的情況下獲取隨機數是具備一定風險的,并有可能導致被惡意攻擊。
隨機數生成漏洞并不像預言機操縱攻擊或重入攻擊那樣普遍,但它們在Solidity教育材料中可是“常客”。
許多教育內容誤導區塊鏈開發人員使用如下代碼獲取隨機數:
```javascriptuintrandomNumber=uint(keccak256(abi.encodePacked(nonce,msg.sender,block.difficulty,block.timestamp)))%totalSize;```
中國少年兒童文化藝術基金會即將發行版權數字藏品NFT:金色財經報道,中國少年兒童文化藝術基金會即將發布“致敬英雄 童心繪夢” 版權數字藏品NFT,收益所得將全部捐贈給公益事業,推動區塊鏈、人工智能等數字技術,助力公益實踐。[2022/6/1 3:55:42]
這里的想法是使用nonce、塊難度和時間戳的某種組合來創建一個"隨機"數字。
然而,這有幾個明顯的缺點——你可以很輕易的用取消交易的方式重復生成多次,直到得到一個你想要的隨機數。
1.使用像block.difficity這樣的哈希對象作為源來生產隨機數時,礦工有能力改變這個源。與"重滾"策略類似,如果結果對他們不利,礦工可以利用他們訂購交易的能力,將某些交易排除在區塊之外。
如果該交易是用于鏈上生成隨機數的源,礦工也可以選擇扣留對他們不利的哈希值所在的區塊。
2.使用block.timestamp無法提供任何隨機性,因為時間戳是任何人都可以預測的。以這種方式使用鏈上隨機數生成器,會讓用戶以及礦工對"隨機"數字產生影響和控制。
如果你希望實現一個公平系統,以這種方式生成隨機性將非常有利于攻擊者,并且這個問題只會隨著隨機函數所保護的價值量的增加而變得更糟,因為攻擊它的動機也增加了。
解決方案:使用ChainlinkVRF作為可驗證的隨機數生成器
為了防止被惡意攻擊,開發者需要一種方法來生成可驗證的隨機數,并防止其被礦工和用戶篡改。
實現這一目標需要來自于預言機的鏈下隨機數源。
然而,許多提供隨機性來源的預言機沒有辦法真正證明他們提供的數字確實是隨機產生的。
因此開發者需要能夠從鏈外獲取隨機性,同時也需要一種密碼學算法來證明隨機性沒有被操縱過。
Chainlink的可驗證隨機函數正好實現了這一點。它使用預言機節點在鏈外生成一個隨機數,并對該數字的完整性進行加密證明。然后由VRF協調器在鏈上檢查加密證明,以驗證VRF的確定性和防篡改性。
它的工作原理是這樣的:
1.一個用戶從Chainlink上節點請求一個隨機數,并提供一個種子值,隨后Chainlink將會發出一個鏈上事件日志。
2.鏈外的Chainlink預言機讀取該日志,并使用可驗證的隨機函數基于節點的密鑰哈希、用戶給定的種子和發送請求時未知的塊數據創建一個隨機數和加密證明。然后,它在第二筆交易中把隨機數返回鏈上,這時在鏈上通過VRF協調器合約使用加密證明進行驗證。
ChainlinkVRF是如何解決上述問題的?
1.無法進行回滾攻擊
由于這個過程需要兩筆交易,第二筆交易是創建隨機數的地方,所以你無法看到隨機數或取消你的交易。
2.礦工無法改變這個值
由于ChainlinkVRF不使用礦工可以控制的參數,比如block.difficulty或block.timestamp等可預測的值,所以他們無法控制隨機數。
用戶、預言機節點或DApp開發者無法操縱ChainlinkVRF提供的隨機性數據,這使得它成為智能合約應用所使用的鏈上隨機性來源的安全得到了保證。
大家可以按照文檔的要求試試在代碼中實施ChainlinkVRF,或者根據我們的初學者指南來使用ChainlinkVRF。
在本系列接下來的內容中,將會為大家逐一講解剩余的7大DeFi安全最佳實踐方式,歡迎持續關注!
關注CertiK官方公眾號,底部對話框發送消息“圖譜”,可獲取《區塊鏈知識圖譜》高清大圖哦!
參考鏈接:
1.?https://www.researchgate.net/publication/235301171_The_Adoption_of_Electronic_Banking_Technologies_by_US_Consumers
2.https://www.gemini.com/cryptopedia/the-dao-hack-makerdao
3.https://docs.soliditylang.org/en/v0.8.9/contracts.html?highlight=receive#special-functions
4.?https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/
5.?https://eips.ethereum.org/EIPS/eip-1884#motivation
6.?https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol
7.?https://fravoll.github.io/solidity-patterns/checks_effects_interactions.html
8、https://blog.chain.link/flash-loans-and-the-importance-of-tamper-proof-oracles/
9.https://www.coindesk.com/flash-loans-centralized-price-oracles
10.https://github.com/Uniswap/uniswap-v2-core/tree/4dd59067c76dea4a0e8e4bfdda41877a6b16dedc
11.https://chain.link/data-feeds
12.https://docs.chain.link/docs/using-chainlink-reference-contracts/
13.https://docs.chain.link/docs/get-the-latest-price/
14.https://docs.chain.link/docs/beginners-tutorial/
15.https://ethernaut.openzeppelin.com/level/0x0b0276F85EF92432fBd6529E169D9dE4aD337b1F
16.https://docs.chain.link/docs/get-a-random-number/
17.https://docs.chain.link/docs/get-a-random-number/
18.https://docs.chain.link/docs/intermediates-tutorial/
來源:金色財經
OpenSea是最大的NFT市場,憑借先發優勢,現在每個月處理著幾十億美元的交易,幾乎處于壟斷地位。所以這也出現了很多OpenSea的挑戰者.
1900/1/1 0:00:0012月6日,國家語言資源監測與研究中心發布“2021年度十大網絡用語”,元宇宙一詞赫然于列。大廠入場元宇宙不足為奇,但元宇宙赫然成為網絡十大熱詞之一,可以想象該詞及背后的信息在網絡中被傳播所達到.
1900/1/1 0:00:00BTC:大餅在經過這波瀑布洗禮之后,價格短線走弱已經是事實。已經把之前的上升趨勢線已經跌破了,近期可能都要走一波震蕩修復的行情,但是這個位置也不要盲目的去追空.
1900/1/1 0:00:0011月20日,三箭資本聯合創始人ZhuSu因不滿以太坊高昂的GAS費用,發推宣布棄用以太坊,不過就在12月7日,三箭資本又從各大交易平臺轉出91,477枚ETH(價值約4億美元).
1900/1/1 0:00:00頭條 ▌元宇宙入選騰訊“2022年最受關注的22項新興技術”榜單12月6日消息,日前,騰訊科技發布了“2022年最受關注新興技術”榜單,一共22項,元宇宙入選.
1900/1/1 0:00:00點擊上方“藍色字”可關注我們!暴走時評:該公司首席執行官SamBankman-Fried將要求投資者以80億美元的估值購買其美國子公司FTX.US的股份.
1900/1/1 0:00:00