BTCV高分资讯 > 数字货币 > 智能合同开发必须读:这10个坚实的安全问题不可

智能合同开发必须读:这10个坚实的安全问题不可

作者:高分资讯来源:高分资讯 数字货币 2020年07月07日

智能合同的安全性令人担忧。了解2020年稳健性的10个常见安全问题。

原标题:《Solidity 十大常见安全问题》

作者:埃雷兹亚龙

翻译:连登社区

在2018年,我们(CheckMarx)对智能合同的安全状态进行了初步研究,重点是Solidity[1]编写的智能合同。当时,我们根据已发布的合同源代码编译了十个最常见的智能合同安全问题(译者注:本文称为扫描合同,本文中出现的x%就是基于此)。两年后,是时候更新研究和评估智能合同安全的发展了。

其他值得注意的问题虽然有一个安全问题排名很好,但它通常有一些有趣的细节,因为有些细节与排名列表不完全一致。在深入研究前10个问题之前,有必要解释一下原始研究中的一些亮点:

2018年,两个最重要的问题是外部合约拒绝服务重入。但现在这些问题已经得到缓解(但仍值得关注)。您可以从我们的研究博客中了解更多关于可重入性的信息:从安全性的角度来看智能合同[2]。

译者注:事实上,由于DeFi应用程序(如闪电贷款)的联合应用,导致了许多严重的再入攻击。

现在Solidity v0.6.x已经发布[3],这带来了许多重大变化[4]。然而,50%的扫描智能合同甚至还没有准备好使用solidty v 0 . 5 . 0编译器。此外,30%的智能合同使用过时的语法(如sha3、throw、constant等)。),并且83%的合同在指定的编译器版本中存在规范问题(pragma)。

译者注:Solidity 0.6在语义上更清晰(例如,继承中0.6的升级[5]),这有助于编译器及时发现问题并使代码更安全。

尽管能见度问题[6]没有出现在2018年或今年的前10名中,但能见度问题增加了48%,这值得关注。

下表比较了2018年和2020年十大常见问题列表之间的变化。这些问题按严重程度和流行程度分类:

智能合约开发必读:这 10 个 Solidity  安全问题不容忽视

1.未检查的外部呼叫是2018年Solidity十大安全问题列表中的第三个常见问题。现在前两个问题已经解决,未检查的外部调用已经成为2020年更新名单中最常见的问题。

调用实性底部的方法,如address.call(),不会引发异常。相反,当遇到错误时,它会返回false。

另一方面,当调用externalcontract。dosome()使用契约,如果dosome()抛出异常,该异常将继续“冒泡”。

应该通过检查返回值来显式处理不成功的情况。以下使用addr.send()进行以太网传输的例子是一个很好的例子,它也适用于其他外部呼叫。

如果(!addr.send(1)) {

恢复()

}

2.高成本周期高成本周期从坚固性安全列表中的第四位上升到第二位。受此问题影响的智能合同数量增加了近30%。

众所周知,在以太网上操作是要收费的。因此,减少完成操作所需的计算不仅是一个优化问题(效率),而且还涉及成本。

循环是一个昂贵的操作。这是一个很好的例子:数组中的元素越多,完成循环所需的迭代次数就越多。最终,无限循环将耗尽所有可用的气体。

对于(uint 256 I=0;I .要素.长度;i ) {

//做某事

}

如果攻击者能够影响元素数组的长度,上述代码将导致拒绝服务(执行不能跳出循环)。然而,8%的扫描智能合同存在阵列长度操纵问题。

3.权力过大的所有者这是军人十大安全问题中的一个新问题,影响了约16%的合同。有些合同与其所有者密切相关,有些函数只能由所有者地址调用,如下例所示:

智能合约开发必读:这 10 个 Solidity  安全问题不容忽视

只有合同所有者可以调用dosome()和doSomethingElse()函数:前者使用onlyOwner修饰符,而后者显式执行修饰符。这带来了严重的风险:如果所有者的私钥被泄露,攻击者就可以控制合同。

4.算术精度问题由于使用256位虚拟机(EVM[7]),实体的数据类型有些复杂。可靠度不提供浮点运算,小于32字节的数据类型将被打包到同一个32字节的槽中。考虑到这一点,您应该预见到以下程序准确性问题:

函数计算奖金(uint金额)返回(uint) {

返回金额/分隔符*奖金;

}

如上面的例子所示,在乘法之前执行的除法可能有很大的舍入误差。

5.依赖tx.origin的智能合同不应依赖tx.origin进行身份验证,因为恶意合同可能会实施中间人攻击并耗尽所有资金。建议使用msg.sender代替:

功能转移至(地址目的地,单位金额){

要求(tx.origin==owner) {

转账(金额);

}

}

关于Tx起源攻击的详细描述可以在实性文件[8]中找到。简单地说,tx.origin始终是合同呼叫链中的初始发起者帐户,而msg.sender代表直接呼叫方。如果链中的最后一个合同依赖于tx.origin进行认证,则呼叫链中间环节的合同将能够耗尽被叫合同的资金,因为认证并不检查谁进行了呼叫。

6.上溢/下溢实性的256位虚拟机存在上溢和下溢问题(译者注:因为结果超出了值的范围,所以称为上溢),这里[9]有一个具体的分析。当在for循环条件中使用uint数据类型时,开发人员应该格外小心,因为这可能导致无限循环:

for (uint i=边界;I=0;i - ) {

ans=I;

}

在上面的例子中,当I的值是0时,下一个值是2 256-1,这使得条件总是为真。开发人员应该尝试使用,比较=与==。

7.不安全类型的推断这个问题在十大安全问题排名中上升了两个位置,现在它比以前影响了超过17%的智能合同。

稳固性支持类型派生,但是有一些奇怪的表现。例如,文字0将被推断为字节类型,而不是通常预期的整数类型。

在下面的示例中,I的类型被推断为uint8,因为此时存储I的值uint8就足够了。但是如果元素数组包含超过256个元素,下面的代码将溢出:

对于(var I=0;I .要素.长度;i ) {

//对某事

}

建议显式声明数据类型,以避免意外行为和/或错误。

译者注:变量定义变量已在实度0.6中删除(实度0.6之后没有类型派生),如果使用新的编译器,这不会是一个问题。

8.在Solidity的十大安全问题列表中,错误转移从第六位降至第八位,目前影响不到1%的智能合同。

有许多方法可以在合同之间转移以太网。尽管官方建议使用addr.transfer(x)函数,但我们仍然发现仍然使用send()函数的智能契约:

如果(!addr.send(1)) {

恢复()

}

请注意,如果转移不成功,addr.transfer(x)将自动抛出异常,这也将缓解第一个未检查的外部调用的问题

9.环内转账在环内以太网中转账时,如果其中一笔转账失败(例如,合同不能被接受),整个交易将被回滚。

对于(uint I=0;I .用户.长度;i ) {

用户[i]。转账(金额);

}

在本例中,攻击者可能利用这种行为进行拒绝服务攻击,从而阻止其他用户接收以太网。

10.时间戳依赖在2018年,时间戳依赖问题排名第五。请务必记住,智能合同在不同时间运行在多个节点上。以太网虚拟机(EVM)不提供时钟时间,现在通常用于获取时间戳的变量(block.timestamp的别名)实际上是矿工可以操作的环境变量。

if(TimeHascome==block . timestamp){

赢家.转移(金额);

}

因为矿工可以操纵当前的环境变量,所以他们的值只能用在不等式中。

如果您的应用程序需要随机性,您可以参考RANDAO契约[10],它基于任何人都可以参与的分散式自治组织(DAO),并且是由所有参与者生成的随机数。

当总结和比较2018年和2020年的十大常见问题时,我们可以观察到在开发最佳实践方面的一些进展,尤其是那些影响安全性的问题。看到2018年最大的两个问题:未检查的外部调用外部合约拒绝服务不再在名单上,这是一个积极的信号,但仍需要采取措施来避免此类常见错误。

请记住,智能契约在设计中是不可变的,这意味着一旦创建,源代码就无法修补。这给安全带来了巨大的挑战。开发人员应该利用可用的安全测试工具,以确保源代码在部署之前得到充分的测试和审计。

稳健性是一种非常新和成熟的编程语言。Solidity v0.6.0引入了一些重要的变化[11],预计在未来的版本中将会有更多的变化。

来源链接:securityboulevard.com

标签: btcv