当前位置:首页区块链智能合约开发必读:这10个常见的安全问题值得关注

智能合约开发必读:这10个常见的安全问题值得关注

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

原文标题:埃雷兹亚龙
著《坚固性的十大常见安全问题》,译:邓连社

2018年,我们(checkmarx)对智能合约的安全状况进行了初步研究,重点关注SOLidity[1]编写的智能合约。当时,我们根据公开的合同源代码编写了最常见的10个智能合约安全问题。两年后,更新研究并评估了智能合约安全性的发展。

其他值得注意的问题

虽然有一个很好的安全问题排名,它往往有一些有趣的细节,因为有些细节并不完全符合排名表。在深入探讨10大问题之前,有必要详细阐述原始研究中的一些亮点

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

译者注:事实上,由于DeFi应用程序(如快速贷款)的组合,出现了一些严重的重入攻击。

现在是SOLidness 0.6版。X已经发布了[3],并带来了许多重大变化[4],但50%的扫描智能合约甚至还没有准备好使用SOLidity 0.5.0编译器。此外,30%的智能合约使用过时的语法(例如,使用Sha3、throw和constant等),83%的合约在指定的编译器版本中存在规范问题(pragma)。

Solidness ;0.6在语义上更加明确(例如,在0.6版本中升级了继承),这有助于编译器及时发现问题并使代码更安全,

尽管可见性问题[6]没有出现在2018年的前10个职位中,也没有出现在今年的前10个职位中,但可见性问题增加了48%,值得关注。

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

1未检查外部呼叫

第三个常见问题是2018年10大安全问题列表中未经检查的外部电话。由于前两个问题现已解决,未经检查的外部呼叫是2020年年度更新列表中最常见的问题。

Solidity基础调用方法(例如;地址.呼叫())不会引发异常。遇到错误时,返回false。

如果合同用于调用;外部合同.doSom如果dosom HT5 ing()引发异常,则异常将继续“气泡”传播。

应使用以下方法通过检查返回值来明确处理失败:发送地址()进行以太网传输是一个很好的例子,它也适用于其他外部呼叫。

 if(!addr.send(1)) { reert() }

2高成本周期

高成本周期从第四位上升到第二位。受问题影响的智能合约数量增加了近30%。

众所周知,HT3的计算需要支付。因此,减少完成一个操作所需的计算不仅是一个优化问题(效率),而且也是一个成本。

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

 for(uint256 i=0; ilt; elements.length; i++) { // do som HT5 ing }


如果攻击者可以影响元素数组的长度,则上述代码将导致拒绝服务;(执行无法跳出循环)。在扫描的智能合约中,发现8%的合约存在阵列长度操纵问题。

3权力过大的业主

这是稳健性安全性十大安全问题中的一个新问题。此问题影响约16%的合同。有些合同与其所有者关系密切,有些函数只能由所有者地址调用,如下例所示:

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

4算术精度

由于使用256位虚拟机(EVM[7]),因此坚固性的数据类有些复杂。Solidity不提供浮点运算,小于32字节的数据类打包到同一个32字节槽中。考虑到这一点,您应该预料到以下程序精度问题:

 function calculateBonus(uint amount) returns (uint) { return amount/DELIMITER*BONUS; }


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

5AMPL依赖性;发送来源

智能合约不应依赖;发送来源;身份验证,因为恶意合同可能会遇到中间人攻击并耗尽资金。建议改用;消息发送者:

 function transferTo(address dest, uint amount) { require(tx.origin == owner) { dest.transfer(amount); } }


您可以在SOLidity文档中找到有关发送源攻击[8]的详细说明。简而言之,发送来源;始终是合同调用链中的原始发起人帐户,并且;消息发送者;表示直接呼叫方。如果链中的**一个合同取决于;发送来源如果进行身份验证,位于呼叫链中间的合同将能够挤压被呼叫的合同的资金,因为认证不检查它是谁(消息发送者)打过电话。

6溢出/下溢

256位SOLidity虚拟机存在溢出和下溢问题。开发人员在for循环条件中使用uint数据类时应格外小心,因为它可能导致无限循环:

 for (uint i = border; i gt;= 0; i--) { ans += i; }


在上面的示例中,当I的值为0时,下一个值为2^256-1,这使得条件始终为真。开发人员应尽量使用;,!=和===用于比较。

7不安全类派生

这一问题在稳固性十大安全问题列表中上升了两位,现在影响智能合约的数量比以前增加了17%。

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

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

*


 for (ar i = 0; i lt; elements.length; i++) { // to som HT5 ing }


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

译者注:在SOLidity 0.6删除VAR定义变量后,SOLidity 0.6之后不再有类派生,如果使用新的编译器就不会有问题。

8不正确的传输

该问题已从第六位下降到第八位,在十大安全问题列表的稳固性,目前不影响1%的智能合约。

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

*


 if(!addr.send(1)) { reert() }


请注意,如果转账不成功,则;地址转移(x) 会自动引发异常,这也会减轻第一个未经检查的外部调用的问题

9周期内转移

当在循环体中进行以太传输时,如果其中一个传输失败(例如,无法接收到一个合同),则会回滚整个事务。

 for (uint i = 0; i lt; users.leng HT h; i++) { users[i].transfer(amount); }


因此,在该示例中,攻击者可以使用该拒绝服务来阻止其他用户的攻击。

10 时间戳相关性

在2018年,时间戳依赖性问题排名第五,必须记住,智能合约在不同时间在多个节点上运行。HT3虚拟机(EVM)不提供时钟时间,通常用于获取时间戳(阻止时间戳实际上是矿工可以操纵的环境变量。

*


 if (timeHasCome == block.timestamp) { winner.transfer(amount); }


由于矿工可以操纵当前的环境变量,因此它们的值只能用于不等式中。

如果您的应用程序需要随机性,您可以参考randao合同[10],它基于任何人都可以参与的去中心化自治组织(DAO),它是由所有参与者生成的随机数。

总结

在比较2018年和2020年十大常见问题时,我们可以看到在制定**做法方面取得了一些进展,尤其是那些影响安全的做法。看到2018年排名前2位的问题:外部合同拒绝服务和重新进入已不在名单上,这是一个积极的信号,但仍需采取措施避免此类常见错误。

记住,智能合约在设计上是不可变的,这意味着一旦创建,源代码就无法修补。这对安全构成了巨大挑战。开发人员应该使用可用的安全测试工具来确保源代码在部署之前经过了充分的测试和审计。

Solidity是一种非常新且仍然成熟的编程语言,Solidity 0.6.0引入了一些重要的更改[11],预计在未来的版本中还会有更多的更改。

源链接:securitybouleard.com网站

温馨提示:

文章标题:智能合约开发必读:这10个常见的安全问题值得关注

文章链接:https://www.btchangqing.cn/50445.html

更新时间:2020年07月07日

本站大部分内容均收集于网络,若内容若侵犯到您的权益,请联系我们,我们将第一时间处理。

区块链

卡尔达诺可以查看蜀挑战以太坊状态吗?

2020-7-7 4:34:47

区块链

“区块链工程技术人员”和“区块链应用运营商”是做什么的?

2020-7-7 7:21:28

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索