智能合约是区块链的核心技术之一,是多方参与场景中的共识规则,更是智能合约是价值传递的中枢。之所以区块链出现以后安全问题变得前所未有的重要,是因为智能合约实现的是一种价值传递,区块链上的每一个数字都是价值,每个漏洞导致的数字变化,其背后就是巨额的价值损失。
2016年6月The DAO安全漏洞,导致5000万美元的损失 2017年7月Parity多签名钱包两次安全漏洞,分别导致3000万美元、1.52亿美元的损失。 2018年4月BEC代币被盗事件,由于一行代码的安全漏洞引发其9亿美元市值几乎归零。
1
美链BEC合约漏洞
BEC漏洞实质上是一个算法上下溢出漏洞。该漏洞的原理在于,当合约提供提款或是转账功能时,一般会对地址的余额做操作,如果余额操作没用SafeMath则攻击者可以经过巧妙设计将转账的扣款金额弄成0,而转出金额弄成很大的数值,导致合约凭空产生很多token或用户凭空从合约中提出很多余额。
由此可见不止合约中的计算,程序中的所有计算都需要关心上下溢出问题,如果发生溢出漏洞则会产生很大的损失。
2
假充值漏洞
在用户进行转账时,一些合约的transfer函数对转账发起人(msg.sender)的余额检查用的是if判断方式,而这种温和的判断方式在transfer这类敏感函数场景中并非一种严谨的编码方式,而这种不严谨的编码方式是一种安全缺陷,这种安全缺陷可能会导致特殊场景下的安全问题。攻击者可以利用存在该缺陷的合约向中心化交易所、钱包等服务平台发起充值操作,若交易所仅判断如TxReceiptStatus是success,则就有可能以为充值成功,产生“假充值”“假交易”。
这种问题在于交易所的代码判断需要更加严谨,不止是要判断状态是否正确,还要判断这笔转账确实是到账了的。当然合约代码在这种问题的判断中也需要尽量避免使用if这种温和的判断方式,而应该直接用assert、require这种语句让条件不成立的情况下结果状态不为Success。
3
TheDAO事件
TheDAO事件本质上是由重入漏洞引起的。重入攻击流程如下:
1. 一个聪明的合同跟踪一些外部地址的平衡,并允许用户通过其公共资金检索withdraw( )功能。
2. 一个恶意的智能合同使用withdraw( )函数检索其全部余额。
3. 在更新恶意合同的余额之前,受害者合同执行call.value(amount)( )低级别函数将以太网发送给恶意合同。
4. 该恶意合同有一个支付fallback( )接受资金的功能,然后回调到受害者合同的withdraw( )功能。
5. 第二次执行会触发资金转移:请记住,恶意合同的余额尚未从首次提款中更新。结果,恶意合同第二次成功退出了全部余额。
其中关键点在于,用户提款时,TheDAO调用了call.value(amount)( )方法将金额发给调用者,问题就在于:如果调用者是个合约地址,该方法就会触发合约的一个回调函数,如果这个调用者合约是个坏合约,它就可以再次触发提款调用,以此递归导致大量金额从合约中提走。详解如下图
因此将call.value(amount)( )改成sender.send(amount),就能避免该重入攻击,但对于DAO事件已于事无补了,因此代码安全审计非常重要。
领取专属 10元无门槛券
私享最新 技术干货