使用“扫一扫”即可将网页分享至朋友圈。
以太坊智能合约为何安全漏洞频发?
最近,随着 DeFi 火热,以太坊智能合约安全漏洞频发。究竟是什么原因造成的,以及如何更好地防范这些漏洞?
概述
相比于比特币而言,以太坊更易发生安全事故。这主要是因为以太坊虚拟机是图灵完备的,以太坊可实现函数间相互调用、嵌套调用,智能合约间相互调用等各种复杂逻辑。而比特币只实现了基于栈的非图灵完备的虚拟机,并只能通过操作码进行入栈和出栈操作。另外比特币也没有复杂的 DApp 应用,所以逻辑上简单,故而没有太多空间引发安全漏洞。
以太坊上各种 DApp 复杂的智能合约逻辑是引发安全漏洞的主因。以太坊智能合约的安全漏洞主要可以分为逻辑问题和合约代码问题两种。
逻辑问题
最近频繁的“闪电贷”攻击是一个典型的逻辑问题引起的安全漏洞。在各种闪电贷攻击中你可以看到清晰的逻辑问题。攻击者只要制造出两个系统之间的价格差,便能通过闪电贷攻击获利。
闪电贷攻击的逻辑细节大家可以阅读之前一篇专门讲闪电贷的文章:“造富神器”闪电贷。本文主要阐述合约代码问题。
合约代码问题
我们知道,几乎稍微复杂一点的代码都或多或少地存在问题(bug)。了解出现问题的原因,并且归纳问题类别可以帮助我们更好地防范它们。下面是 Ownbit 钱包团队整理的关于以太坊智能合约安全最容易出现问题的点。
1. 重入(Reentrancy)
这是排名第一的问题。所谓“重入”就是一个方法被多次循环调用。而这通常是合约开发者所意想不到的。例如一个取款合约:
function withdrawEther() public { uint amount = userBalances[msg.sender]; bool success, ) = msg.sender.call.value(amount)(""); // 这里重入 require(success); userBalances[msg.sender] = 0; }这是一段很简单的取款合约,让用户取走他的 ETH 余额。开发者并没有意识到这段代码可能会被重入。方法是:只要调用者是一个合约账户,那么 msg.sender.call 将默认调用该合约账户的 fallback 函数。攻击者只需要在其 fallback 函数再次调用 withdrawEther 就可以源源不断地取走 ETH。
发生在 2016年6月,著名的 The DAO 攻击,从而导致了 ETC 分叉的事件,就是通过同样的方法实施攻击的。从事后看来,这只是一个小小的程序问题(却造成了如此严重的后果)。要修复这个问题也非常容易,只需要将两行代码调换顺序即可:
userBalances[msg.sender] = 0; (bool success, ) = msg.sender.call.value(amount)("");2. 让你的交易不打包
以太坊区块的打包机制是按照给予的矿工费(GasPrice)进行优先打包,并且每个区块有总 GasLimit 的限制(目前为每区块 1200万 Gas)。所以攻击者可以制造出若干使用 GasLimit 非常大,并且 GasPrice 给得非常高的交易,让它们优先占满区块,从而让目标交易无法被打包。
所以,在编写合约逻辑时,不能假设你的交易会在有限时间内被打包,否则就容易受到此类攻击。著名的“Fomo3D”事件就是用了这样的攻击方法。
Fomo3D 游戏规则是奖励最后一个购得某个商品的人。每次商品被买入将重置该商品的定时器,如果在定时器达到0之前没有其他购买者,则你将获得系统的奖励。攻击者在 Fomo3D 中买入商品,然后同时发送大量占用区块的攻击交易,以至于在接下来的 13 个区块内,其他购买者的交易无法被打包。这时定时器达到 0,并认为无其他购买者。攻击者便获得了奖励,完成了攻击。
3. 错误使用 tx.origin
如果你发现一个合约使用了 tx.origin,那么可以留心一下此处可能存在的漏洞。在大部分情况下,我们应该使用 msg.sender 来替代 tx.origin,因为使用 tx.origin 容易引发安全漏洞。
很多时候,合约开发人员会假定 msg.sender 和 tx.origin 是相等的,但其实不是。例如:用户A 调用 合约B,而 合约B 进一步调用 合约C,那么在合约B和C中 tx.origin 都将是 A,而 msg.sender 则一个是 A,一个是B。
一般攻击者会引诱 A 调用一个诱导合约B,而B再去调用由 A 部署的目标合约C,因为 合约C 错误地使用了 tx.origin,合约B可以通过传递过来的 tx.origin 获得对 合约C 的控制权,从而完成攻击。
4. 溢出攻击
智能合约里的数据是可能溢出的,例如:uint256,你觉得很大:2^256。它的确很大,但依然可以溢出。例如一个合约允许对一个数据进行加减,攻击可以通过对这个数据进行精心策划的调用,让其通过溢出达到允许执行某些逻辑的目的,从而实现攻击。
5. fallback 可以 revert
fallback 是可以 revert 的,就是说,你如果向对方转移 ether,对方可以让你总是不成功。
例如你编写一段合约,并且依赖于你成功向某个地址转移 ether,那么攻击可以部署一个合约,将其 fallback 写成 revert 来让你来的调用总是失败:
function () public payable { revert () ; }6. selfdestruct 可以定义任意受益者,而不会调用 fallback
当你以为可以通过 revert 进行阻止所有人向你付款 ether 时,你可能又错了。攻击者通过创建一个合约,并且然后销毁这个合约。销毁合约以太坊将退还一部分 ether 作为鼓励,而这个退还可以指定任意受益者,而对方的 fallback 函数不会被调用。
这就是说,开发者要意识到你没有办法完全阻止别人向你的合约账户转移 ether。
7. 未正确使用 delegatecall
在使用 delegatecall 时,要注意上下文(即 msg.sender 等)的变化。用 call 进行合约调用时,上下文被切换至被调用合约。而用 delegatecall 进行合约调用时,上下文依然在本合约。
delegatecall 和 call 不同的调用上下文也是合约安全漏洞较常出现的地方。
8. 不同方法传气不一样
当我们进行 ether 转移时,不同的方法传气(Gas)不一样。使用 send() 和 transfer() 传递气仅为 2300,而使用 call.value()() 则将剩余的气全部传递。因此,最新的安全规范是建议使用 call 而不是 send 或者 transfer 进行 ether 转移。
如果你发现一个合约还是使用 send 或者 transfer,那么你可以制造出目标合约,让其转移 Out of Gas。
结语
以上这些点是合约代码最常出现问题的点。每个错误的原因都比较原子化,理解相应的原理可以帮助我们有效地避免这些问题。当合约逻辑复杂时,一定会有更加复杂、隐藏得更深的逻辑问题,这时,这些原子点的检查依然可以帮助我们找到它们。
以太坊智能合约的安全问题主要是因为其“过于灵活”引起的。灵活性和安全性如同天平的两端。以太坊选择了灵活性,某种程度上便把安全性的潜在风险留给了市场。
一个 DeFi 项目能否安全稳定地运行,或是会被黑客攻击,取决于合约开发人员对原理的理解、对细节的把控,以及严肃认真的态度。线上合约犯错的代价是巨大的,这就对合约开发人员提出了更高的要求!
“广东财经网”的新闻页面文章、图片、音频、视频等稿件均为自媒体人、第三方机构发布或转载。如稿件涉及版权等问题,请与
我们联系删除或处理,客服邮箱1098101642@qq.com,稿件内容仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同
其观点或证实其内容的真实性。
- 声音提醒
- 60秒后自动更新
【民政部回应何时恢复婚姻登记】民政部社会事务司二级巡视员杨宗涛表示,婚姻登记场所是人群聚集场所,部分地区暂停婚姻登记工作是对人民群众安全负责。未停止登记的地方推广用电话、网络、qq群预约登记,控制登记人数,分批分段登记,减少人员聚集和在登记机关停留时间。已停止婚姻登记地方将根据当地疫情控制情况逐渐恢复。
15:54欧洲央行副行长金多斯:欧洲央行还没有达到逆转利率。宽松政策的副作用更明显了。
15:54财经网站Forexlive分析师Justin Low评瑞士1月CPI月率:尽管通胀年率保持稳定,但核心通胀率有所下降,这一点令人更加担忧。这只是进一步巩固了瑞士央行维持现有货币政策不变,并可能在未来寻求更多宽松措施的观点。
15:54【武汉两大批发市场商户开业率超过80%】商务部市场建设司司长朱小良10日称,目前武汉生活必需品供应基本正常,除冷鲜肉、鲜叶菜等少数品种存在结构性短缺外,大部分重要生活物资供应充足,未发生明显抢购或脱销断档情况。当地白沙洲和四季美两大批发市场正常营业,商户开业率超过80%,日交易量上升至3000吨以上。(国是直通车)
15:53【日本2019年经常项目顺差增长4.4%】日本财务省10日发布的国际收支初步统计报告显示,主要受外国人入境游消费扩大影响,2019年日本经常项目顺差增长4.4%。报告显示,2019年日本经常项目顺差为20.06万亿日元(1美元约合109.8日元)。其中,商品贸易方面,由于液化天然气价格下跌等因素,进口下降5.6%至75.56万亿日元;由于汽车部件及钢铁等产品出口减少,出口下降6.3%至76.12万亿日元。货物贸易顺差减少53.8%,为5536亿日元。(新华社)
15:53欧元兑美元EUR/USD短线波动不大,现报1.0952。
15:53瑞士1月CPI年率:0.2%,前值:0.2%,预期:0.1%;瑞士1月CPI月率:-0.2%,前值:0%,预期:-0.2%。
15:52英镑兑美元GBP/USD短线走低13点,现报1.2890。
15:52【宁德时代“供电”国产特斯拉 有望拉低售价20%】全国乘联会秘书长崔东树分析认为,“随着特斯拉国产化率提升和产能爬坡,未来特斯拉国产车型的价格下探空间还是很大的。”他预计今年下半年,国产Model 3车型的售价就有望降至25万元,降幅接近20%。(新京报)
15:51【内蒙古:对不裁员或少裁员企业返还上年度50%失业保险费】据内蒙古新型冠状病毒肺炎疫情防控工作指挥部消息,疫情期间,内蒙古对不裁员或少裁员的企业返还上年度实际缴纳失业保险费的50%,对面临暂时性经营困难的中小企业,返还标准提高到上年度6个月企业及其职工缴纳社会保险费的50%。
15:51【商务部:2019年服务进出口总额54152.9亿元 同比增长2.8%】商务部新闻发言人表示,2019年,在服务贸易创新发展试点等政策的激励下,我国服务贸易总体保持平稳向上态势,逆差明显下降,结构显著优化,高质量发展成效初步显现。全年服务进出口总额54152.9亿元(人民币,下同),同比增长2.8%。其中,出口总额19564.0亿元,同比增长8.9%;进口总额34588.9亿元,同比减少0.4%。(第一财经)
15:51【振华股份:疫情导致下游客户开工推迟 产品库存上升】振华化学公告,公司目前生产经营稳定,所有产能均正常开工,原材料采购能基本满足生产需要,由于疫情导致下游客户开工推迟,公司出货量减少,产品库存有所上升。公司将根据客户需求、疫情及市场变化,适度调整生产经营策略,尽可能保持生产经营的稳定。
15:50环旭电子2月10日晚间公告,公司2020年1月合并营业收入为23.27亿元,较去年同期的合并营业收入减少27.83%,较2019年12月合并营业收入环比减少37.23%。
15:49精测电子:与京东方集团签订了多份销售合同,合同累计金额达到6.96亿元。
17:12华夏银行:银保监会同意本公司在全国银行间债券市场发行不超过100亿元人民币的金融债券,募集资金全部用于绿色信贷。
17:03