本教程适用于所有希望向主网推出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造成的。
Shima Capital创始人连续第二年接替Gary Gensler在麻省理工教授加密金融课程:金色财经报道,Shima Capital创始人Yida Gao将重返麻省理工学院,这将是他连续第二年接替美国证券交易委员会主席Gary Gensler在麻省理工教授加密金融课程(15.492 Crypto Finance),该课程探索比特币等加密货币市场,包括加密资产底层区块链技术的基础知识和经济学。Yida Gao在麻省理工学院担任讲师的第一年邀请了以太坊创始人Vitalik Buterin、Animoca Brands 主席 Yat Siu等嘉宾进行演讲,第二年将邀请BitMEX 联合创始人Arthur Hayes、美国证券交易委员会委员Hester Peirce、以及Ripple创始人等。(prnewswire)[2023/4/1 13:39:07]
在该攻击中,Uniswap的功能设计没有遵循已被广泛采用的??"ChecksEffectInteractive"模式,该模式是为了保护智能合约免受重入攻击而发明的,按照该模式,代币转移应该在任何价值转移之前进行。
2.使用DEX或AMM中的代币余额储备作为代币价格参考会产生漏洞
这既是用于攻击协议的最常见方法之一,也是最容易防御的DeFi攻击类型。
使用`getReserves()`来决定代币价格是十分危险的。
当用户通过使用闪电贷攻击基于订单簿或自动做市商(AMM)的去中心化交易所(DEX)中的代币价格,这种中心化的价格预言机就有可能会被攻击。
在被闪电贷攻击时,因为项目使用了DEX中的价格作为他们的价格预言机的数据,导致智能合约的执行出现异常,其形式包括触发虚假清算、发放过大的贷款或触发不公平交易。
由于这个漏洞,即使是市面上主流的DEX——例如Uniswap,?也不建议单独使用代币对(swappair)中两种代币的相对比率作为价格预言机的定价。
在基于DEX或AMM的价格预言机中,预言机的数据源是DEX上一次成功交易,代币对调整之后的代币余额,即代币对中两种代币的相对比率。
该价格可能与代币的实际市场价格不同步。
例如,如果进行了大额交易时代币对中没有足够的流动性来支持,将会导致代币价格与交易所的平均市场价格相比发生较大波动,当用户大量买入时代币价格会飙升,当大量卖出时代币价格会狂跌。
闪电贷加剧了这一问题,因为它允许所有用户在没有任何抵押的情况下获得大量临时资金,以执行大额交易。用户经常将问题归咎于闪电贷,称之为“闪电贷攻击”。
然而,根本问题是——他们自己的DEX使用的是不安全的价格预言机,代币价格很容易被操纵,导致依赖预言机的协议引用了不准确的价格。
1月比特币和以太坊期权、期货交易指标普涨,BTC期权持仓量涨幅达116.5%:金色财经报道,据The Block分析数据显示,1月比特币和以太坊期权、期货交易指标普涨,比特币期权持仓量涨幅达到116.5%,以太坊期权持仓量涨幅为71.7%;比特币期权交易额在1月份增长了107.8%,达到160亿美元;以太坊期权交易额在1月份增长了54.5,达到85亿美元。在比特币和以太坊期货方面,比特币期货持仓量上涨21.3%,以太坊期货持仓量上涨15.9%;在期货交易额方面,比特币和以太坊期货交易额也出现上涨,其中比特币期货交易额在1月增加73%达到6560亿美元。[2023/2/2 11:42:44]
这些攻击应被更准确地描述为“预言机操纵攻击”,这一攻击形式在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);??}}```
该项目有一个预言机机制,可以从DEX中获取代币价格。
在DEX中,用户可以将一对代币存入流动性池合同,允许用户根据汇率在这些代币之间进行交换,汇率根据池中每一方的流动性数量计算。
现在有一个假设,如果一个项目大部分代码是从热门项目Uniswap中拷贝而来,我们可以认为这个项目是安全的。?
然而如果项目方在此基础之上添加了一个奖励代币项目,当用户向LP权益池中存储流动性时,他们不仅可以获得流动性代币LPtoken,还可以获取流动性挖矿的奖励代币。
这种情况下,黑客可以通过闪电贷将大量资金存入流动性池,从而操纵这个奖励代币的铸造功能,这使得他们能够以错误的比率兑换奖励代币。
在下方这个函数中,我们可以看到,攻击者做的第一件事就是根据流动性池中两种资产的储备量,获得流动性池中资产之间的汇率。
澳交所因DLT交易后系统受到股东和央行的抨击:金色财经报道,澳大利亚证券交易所 (ASX) 因其延迟的 CHESS 区块链清算和结算系统遭到股东和中央银行的反对。8月,ASX宣布再次延迟,最早将推出时间推迟到2024年底。埃森哲签约审查代码,据披露,到目前为止已经在该项目上花费了1.5亿美元。
在今天的年度股东大会(AGM)上,关于薪酬方案的投票收到了30%的反对意见,ASX主席Damian Roche称其为\"罢工\"。前任首席执行官Dominic Stevens之前的可变奖励减少了40%,其他ASX在CHESS替代项目上的工作人员也被削减了奖金。[2022/9/29 5:59:44]
下面这行代码的目的是获得流动性池中的代币储备?
```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}```
Convex Finance在Arbitrum上线:金色财经报道,CRV质押和流动性挖矿一站式平台Convex Finance宣布在Arbitrum上线。Arbitrum上用于Convex池的LP代币可以在地址之间转移。另外,Arbitrum上LP的CVX奖励将根据每两周一次的vlCVX衡量权重投票中池的投票比例进行分配。(Medium)[2022/11/18 13:19:51]
在这个例子中,向用户进行奖励代币发放的主要函数是_mint(mintReward,to);。
我们可以看到,该函数根据用户在流动性池上锁定的资产价值来铸造奖励代币。
因此,如果一个用户突然在流动性池中拥有大量的资产,那么该用户可以轻易地为自己铸造大量奖励代币,这部分代币是从其他用户的奖励中窃取的。
然而,目前的利润水平依旧没有达到攻击者的期望。
因此,操纵DEX中代币的价格可以大大提升他们窃取的代币价值。
在这个例子中,合约认为他们给用户发放了价值5美元的奖励代币,但实际上发放了5000美元。
通过这种设置,恶意用户可以很容易地进行闪电贷攻击,将获取的临时资金存入流动性池,铸造大量的奖励,然后偿还闪电贷款,获得的利润由其他流动性提供者承担,从中获利。
为了防止基于闪电贷攻击的价格操纵问题,通常的解决方案是采取DEX市场的时间加权平均价格。
虽然这可以防止闪电贷歪曲预言机价格,因为闪电贷只存在于一个交易或区块中,而TWAP是多个区块的平均值,但这并不是一个完整的解决方案,因为TWAP有其自身的妥协。
在价格剧烈波动时期,TWAP预言会变得不准确,这可能会导致下游事件——如无法在期限内清偿抵押不足的贷款。
此外,TWAP预言没有提供足够的市场覆盖率,因为它只追踪一个DEX中的数据,使其它容易受到不同交易所的流动性或交易量变化的影响,从而影响TWAP预言给出的价格。
解决方案:使用去中心化的预言机网络
与其使用中心化预言机来确定汇率,保证DeFi安全的最佳做法是使用去中心化的多个预言机组成的网络来确定代币的实际市场价格。
一个DEX作为一个交易所是去中心化的,但把它作为定价信息参考时它是中心化的。
正确的做法是:你需要收集所有流动性中心化和去中心化交易所的价格,按交易量加权,并去除偏差值/清洗交易,以获得相关资产全球汇率的去中心化准确视图,确保能反映市场的实际价格。
如果你能获取基于所有交易环境的成交量加权的全球平均值的资产价格,那么闪电贷在单一交易所中操纵资产价格就不是问题。
此外,由于闪电贷款只存在于单个交易中,它们对去中心化的价格源并没有影响,这些价格源在单独的交易中产生具有能代表全球市场的实际价格更新。
David Rubenstein:相信加密货币不会消失:金色财经报道,Carlyle Group联合创始人David Rubenstein在接受采访时表示,他相信加密货币资产将继续存在。他说:“我现在认为,加密货币不会消失。”
虽然他没有购买任何加密资产,但Rubenstein说他正在对数字资产行业进行间接投资。他表示:“因为我认为这个行业不会很快消失。而且我无法从18,000种加密货币中挑选出哪种会成功。但我认为这个行业是不会消失的。”(The Daily Hodl)[2022/10/2 18:37:16]
Chainlink预言机网络的去中心化结构及其实现的广泛市场覆盖,保护了DeFi协议免受闪电贷攻击导致的价格操纵,这就是为什么越来越多的DeFi项目正在集成Chainlink价格反馈机制,以防止价格预言机被攻击,并确保在突发的交易量变化中准确定价。
你不需要再使用`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;```
这里的想法是使用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/
来源:金色财经
歌手林俊杰在推特上宣布,自己买了Decentraland平台上的三块虚拟土地,正式涉足元宇宙世界.
1900/1/1 0:00:00最近一段时间,加密社区中有一个项目颇为火爆,几乎是在一夜之间光速走红,那就是people,也叫做ConstitionDao。People的诞生过程非常神奇,用“魔幻”二字形容都不为过.
1900/1/1 0:00:00DeFi持续火热,带动NFT、GameFi板块的牛市行情,市场掀起多元化浪潮,吸引着无数资本和投资者的踊跃加入。在高收益的驱使下,各大GameFi代币整体走出了漂亮的登高线,销售量和玩家激增.
1900/1/1 0:00:00加密世界中的误解性报道会带来真实的后果,在12月初,作为NFT市场的OpenSea陷入其中。至于原因,只是一些读者误读了彭博社最近报道的一篇文章中的部分信息.
1900/1/1 0:00:00中国市场信息调查业协会区块链委员会常务委员高泽龙2012年中关村大数据日首次举办,今年已步入第十年,这十年见证了中国的数字经济的蓬勃发展,服务了数字经济领域优秀企业逾5000家.
1900/1/1 0:00:00当前,以区块链技术为代表的第四次工业革命席卷而来,区块链的技术应用和通证经济将人类商业带入新的价值时代,区块链正逐渐成为全球经济社会发展的全新引擎力量,其应用生态覆盖经济社会的各个方面.
1900/1/1 0:00:00