首页 > 最新行情 > 正文

智能合约曾一度受人追捧 如今攻击该问谁责?

作者:探其财经时间:2018-07-26来源: 探其财经

  智能合约攻击已经不再是一两次了,甚至导致了几千万美元的盗窃损失,最著名的攻击是DAO事件,这是数字货币世界最受期待的项目之一,同时也是智能合约的改革。

  虽然很多人听说过这些攻击,但是很少人知道到底发生了什么,是怎么发生的,以及如何避免这些错误。

  智能合约是动态的,复杂的以及难以置信地强大。虽然他们的潜力是很难想象,但是也不可能一夜之间就成为了攻击的对象。

  也就是说,对于往后的数字货币,我们可以从之前的错误中学到经验,然后一起成长。虽然DAO是已经发生的事情,但是这对于开发者,投资者,以及社区成员对于智能合约攻击来说,都是一个很好的例子。

攻击#1:重入攻击

  当攻击者通过对目标调用提款操作的时候,重入攻击就会发生,就好像DAO事件一样。

  当合约不能在发出资金之前更新状态(用户余额),攻击者就可以连续进行提取函数调用,来获得合约中的资金。任何时候攻击者获得以太币,他的合约都会自动地调用反馈函数,function (),这就再次调用了提现合约。

  这时候,攻击就会进入递归回路,这时候这个合约中的资金就会转入攻击者。

  因为目标合约都在不停地调用攻击者的函数,这个合约也不会更新攻击者的余额。当前的合约不会发现有任何问题,更清楚地说,合约函数中包含反馈函数,当合约收到以太币和零数据的时候,合约函数就会自动执行。

攻击流程

  1.攻击者将以太币存入目标函数

  2.目标函数就会根据存入的以太币而更新攻击者的约

  3.攻击者请求拿回资金

  4.资金就会退回

  5.攻击者的反馈函数生效,然后调用提现功能

  6.智能合约的逻辑就会更新攻击者的余额,因为提现又被成功调用

  7.资金发送到攻击者

  8.第5-7步重复使用

  9.一旦攻击结束,攻击者就会把资金从他们自己的合约发送到个人地址

  

1*UeDgMZo2n0skHzgkl352zQ

 

重入攻击的递归回路

  很不幸地是,一旦这个攻击开始,无法停下。攻击者的提现功能会被一次次地调用,直到合约中的燃料跑完,或者被害者的以太币余额被消耗光。

代码

  下面就是DAO合约的简单版本,其中会包括一些介绍来为这些不熟悉代码/ solidity语言更好地理解合约。

  如果我们看下函数withdraw(),我们可以看到DAO合约使用address.call.value()来发送资金到msg.sender。

  不仅如此,在资金发出后,合约会更新credit[msg.sender]的状态。攻击者在发现了合约代码中的问题,就能够使用类似下面的ThisIsAHodlUp 合约。

  需要注意地是,这个后退函数,function(),会调用DAO或者babyDAO的提现函数,来从合约中盗取资金。从另个方面来说,当攻击者想要把所有偷窃来的资金赚到他们的地址,drainFunds()功能会被调用。

解决方案

  现在,我们应该清楚重放攻击会利用两个特别的智能合约漏洞。

  第一个是当合约的状态在资金发出之后,而不是之前进行更新。由于在发出资金前无法更新合约状态,函数就会在中间计算的时候被打断,合约也认为资金其实还没有发出。

  第二个漏洞就当合约错误地使用address.call.value()来发出资金,而不是address.transfer() 或者 address.send()。这两个都受限于2300gas,只记录一个事件而不是多个外部调用。

攻击2:下溢攻击

  虽然DAO合约不会让受害者掉入下溢攻击,我们能够通过现有的babyDAO contract来更好地理解这些攻击为什么会发生。

  首先,我们需要理解什么是256单位制。一个256单位制是由256个字节组成。以太坊的虚拟机是使用256字节来完成的。因为以太坊虚拟机受限于256字节的大小,所以数字的范围是0到4,294,967,295 (2²⁵⁶)。

  如果我们超过这个范围,那么数字就会重置到范围的最底部(2²⁵⁶ + 1 = 0)。如果我们低于这个范围,这个数字就会重置到这个范围的顶端(0–1= 2²⁵⁶)。

  当我们从零中减去大于零的数,就会发生下溢攻击,导致一个新的2²⁵⁶数集。现在,如果攻击者的余额发生了下溢,那么这部分余额就会更新,从而导致整个资金被盗。

攻击流程

  攻击者通过发出1Wei到目标合约,来启动攻击。

  合约认证发出资金的人

  随后调用1Wei的提现函数

  合约会从发送者的账户扣除的1Wei,现在账户余额又是零

  因为目标合约将以太币发给攻击者,攻击者的退回函数被处罚,所以提现函数又被调用。

  提现1Wei的事件被记录

  攻击者合约的余额就会更新两次,第一次是到零,第二次是到-1。

  攻击者的余额回置到2²⁵⁶

  攻击者通过提现目标合约的所有资金,从而完成整个攻击

代码

解决方案

  为了防止受害人陷入下溢攻击,最好的方法是看更新的状态是否在字节范围内。我们可以添加参数来检查我们的代码,作为最后一层保护。函数withdraw()的首行代码是为了检查是否有足够的资金,第二行是为了检查超溢,第三个是检查下溢。

  需要注意,就像我们之前讨论,我们上面的代码是在发出资金之前更新用户的余额。

攻击#3:跨函数竞争条件

  最后要说的,就是跨函数竞争攻击。就像在重放攻击中所说,DAO合约不能正确的更新合约状态,并且可以让资金被盗窃。DAO问题和外部调用中的部分原因是跨函数竞争条件攻击的潜在原因。

  虽然以太坊中所有的转账是线性发生(一个在另一个后面), 外部调用(另一个合约或者地址的调用)如果没有被合理管理,就会成为灾难的导火线。

  在现实世界中,他们是完全可以避免的。当两个函数被调用并且分享同个状态,跨函数竞争条件攻击就会发生。这个合约就会想到,现在有两个合约状态存在,但是现实是只有一个真正的合约状态存在。

  我们不能同时获得X = 3和X = 4这两种结果。 让我们用一个例子来说明这个内容。

攻击和代码

  上面的合约有2个功能 – 一个是可以转移资金,另一个是提现资金。我们假设攻击者调用了函数transfer(),然后同时使用外部调用函数withdrawalBalance()。userBalance[msg.sender]的状态通过2个不同的方向被抽出。

  用户的余额还没有被设为0,但是尽管资金已经被提取,攻击者也能够转移资金。这样情况下,合约可以让攻击者使用双花,这也是区块链技术想要解决的问题之一。

  注意:如果有函数分享状态,跨函数竞争条件攻击就会在多个合约中发生。

  -在调用外部函数之前,应该完成所有的内部工作

  -避免发生外部调用

  -在不可避免地时候,使用外部函数“不可信”

  -在外部调用不可避免的情况下,使用互斥

  根据下面的合约,我们可以看到一个例子1) 在完成外部调用之前,完成内部工作。2)将所有外部调用都设为“不可信”。我们的合约会让资金发送到一个地址,并且允许用户一次性将资金存入合同。

  我们可以看出,这个合约的首个函数在发送资金到用户的合约/地址的时候,就会发生外部调用。同样地,奖励函数在发送一次性奖励的时候,也会使用提现函数,因为这也是不可信的。

  同样重要地是,合约需要执行所有内部工作。就好像重入攻击,函数untrustedGetReward()会在允许提现之前,让用户获得一次性的奖励,从而防止跨函数竞争条件攻击。

  在真实世界,智能合约不需要依赖于外部调用。

  事实上,外部调用在很多情况下,在工作环境中都几乎不可能发生的。由于这个原因,使用互斥体来“锁定”一些状态,并且让拥有者有能力去改变状态,可以帮助防止这类灾难。

  虽然互斥体非常有效,但是当用于多个合约的时候,都会变的很棘手。如果你使用互斥体来防止这类攻击,你需要很仔细地确保没有其他方法来锁定,或者永远不会释放。

  如果使用互斥体的方法,在写入智能合约的时候,你需要保证你完全理解潜在的危险。

  以上,我们可以看到合约mutexExample()会有私人锁定状态,来实行deposit()函数功能和withdraw()函数。锁定会防止用户能够在所有的初步调用完成之前,成功完成withdraw()调用,可以防止任何种类的跨函数竞争条件攻击。

该文章同时收录在:

相关文章

查看更多

相关问答

  • 100万台币等于多少人民币

    回答:100万新台币约等于229158人民币,交易时以银行柜台成交价为准。也就是说,每月的100万台币折合成人民币大约是23万。新台币(货币代码:TWD;货币符号:NT$)是中国台区通用货币。按照现在的兑换标准来看,1新台币约等于0.2292人民币,1人民币约等于4.3638新台币。

  • 第三套房贷款利率

    回答:实际上,根据政策规定,银行已经停止办理第三套房贷款,但是还是可以办理抵押贷款的。如此一来,贷款利率一般都是在央行基准贷款利率的基础上上浮30%—50%。除此之外,购置第三套房的税率也有所增加,通常是3%—5%。

  • 全球黑卡至尊卡是什么

    回答:全球黑卡至尊卡指的是环球黑卡,是杭州冒险元素网络技术有限公司旗下品牌,它是一张特权俱乐部会籍卡。俱乐部通过整合资源,发行特权,为会员提供全方位精英生活服务,如:机场优先排队、酒店底价、餐厅五折、信用签单、定制旅行/商品/活动、真人管家等。所有特权可通过“环球黑卡”App调用。

  • 急需用钱时的最佳办法

    回答:急需用钱时的最佳方法当然是借钱了。向朋友借钱,不需要利息,但要有借有还,避免争端;银行借钱最靠谱,利率最低;支付宝微信借钱最方便快捷,需要有预借额度;另外就是网贷了,申请门款很低,利息偏高,最好选择合法有资质的平台。

  • 分期乐每一笔上征信吗

    回答:分期乐并不是每一笔订单都上征信,目前分期乐提供资金的放款方大部分都是上人行征信的。借款人在借款时,可以注意协议中是否有说明借款记录上征信,如果已经注明了,那么本次贷款就是上征信的。

  • 信用卡还款方式有哪些

    回答:一般分为三种:最低还款、分期还款和全额还款。最低还款:最低还款额是指持卡人在到期还款日(含)前偿还全部应付款项有困难的,可按发卡行规定的最低还款额进行还款,但不能享受免息还款期待遇,最低还款额为消费金额的10%加其他各类应付款项。

查看更多

1875
意见反馈