基于区块链的智能合约安全(二)——已知的漏洞和陷阱 – 作者:DigApis

在这个系列的前一部分,我们分析了与部署在公开区块链上的自动化执行智能合约有关的风险。我们也介绍了一些获得高关注度的智能合约的例子,这些案例造成大量钱财损失,还改变了我们看待区块链上的商业活动的方式。

在这一部分我们会回顾一些已知的问题和漏洞。

 

私钥泄露

 

使用不安全的私钥确实是一个常见的用户错误案例,甚至比漏洞还要常见。然而,我们也需要提这一点,因为它经常发生,而且某些玩家专门利用它从不安全的地址偷资金

最常见的情况是在产品中使用生成地址(例如用在测试工具中的,如Ganache /TestPRC)。这些地址是由公众所知的私钥生成的。一些用户甚至在不知不觉中将这些密钥导入钱包软件,通过原始种子生成秘钥。

攻击者检测这些地址,任何转移到这个在以太币网络主地址的金钱都会立即消失

一个有趣的文章研究了这项非常有利可图的“清扫”活动,并且发现一个清扫人员账户已经设法积累了2300万美元的资金。

 

可重入性和竞争条件

 

如果一个功能模块在完成前调用了很多次,可能会出现意想不到的行为,在某些意想不到的行为中可能存在可重入性漏洞。

让我们来看看下面这个函数,这个函数可用于从一个合约中取回访问者的总余额。

 

去.png

 

call.value()函数可以导致合约外部的代码执行。我们可以把调用者假设成一个数字加密货币钱包软件,也可能是其它合同

如果这个访问者是另一个合约,这就意味着这个合约的回退函数被执行了。回退函数的目的就是收到资金。

一个流氓合约,实现一个叫做payout()的回调函数,在余额设置为0之前,再次递归调用payOut(),从而获得比现有余额更多的资金。

这个问题的解决方案是使用可代替的函数sent()或者transfer()。通过为基本核算支付足量的gas,任何再次调用payout()的尝试都将会失败,从而可以防止递归调用。另外(或者是再者),操作的顺序可能被翻转,例如在金钱交易之前把余额设为0。

在第一部分中提及的DAO攻击就用到这个漏洞的一个变种。

 

下溢/上溢

 

余额通常由无符号整数表示,Solidity中通常有256比特数字。当无符号整数下溢或上溢时,它们的值立马就改变了。现在我们来看一个常见的下溢的例子(数字为了可读性缩短了):

   0x0003

   —  0x0004

   ———————-

   0xFFFF

这里很容易就会发现一个问题,减去一个比余额还要大1的数会导致下溢,结果余额会得到一个大数。

也请注意,由于舍入误差,整数计算的除法会非常复杂。

解决方法是总是检查代码中的下溢或上溢。这里有安全库协助检查,例如SafeMath或者OpenZeepelin。

 

交易定单假设

 

交易进入未经证实的交易池并按照某种规律存在于矿工的数据块中,这种规律取决于矿工的交易选择标准,这很可能是一些试图从交易手续费中获取利益最大化的算法,但是也可以是其他的东西。

因此,打包交易的顺序和它的生成顺序完全不同。为此,合约代码不能在交易规则里创造任何假设。

由于交易是可见的,而且这个交易是可以预见的,所以除了执行合约过程中没有预料到的结果,这里还可能有一个攻击向量,这可能是交易中的一个问题,也就是延迟交易可能会被流氓矿工用于个人利益。事实上,在交易之前就需要意识到某些的交易,既可以被矿工利用,也可以被其他的任何人利用。通过支付一个较高的gas,鼓励矿工迅速将其打包,最终交易可以被“overtaken”。

 

时间戳依赖性

 

在区块链中,时间戳是由矿工生成的。因此,合约不需要为了核心操作依赖于数据块的时间戳,例如把它用作生成随机数的种子。Consensys在他们的指南中给出一个12分钟法则,该规则规定,如果你的时间依赖代码能够处理12分钟时间变化,那么使用block.timestamp是安全的。

 

总结

 

到今天为止,我们看了很多获得了高关注度的基于区块链的智能合约攻击的例子,我们也讨论了一些已经发现的常见的漏洞。在下一篇文章中,我们将会介绍一些更复杂的攻击,这些攻击依赖于区块链和特定操作的工作方式。

*参考来源:security of blockchain-based smart contracts II-Konwn Vulnerabilities and Pitfalls,本文由丁牛网安实验室小编EVA编辑整理,如需转载请标明出处。

来源:freebuf.com 2018-03-28 19:54:36 by: DigApis

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论