【Solidity】注意事项

安全注意事项

虽然通常很容易构建按预期工作的软件,但是更难检查没有人可以以预期的方式使用它。

在Solidity中,这更重要,因为您可以使用智能合同来处理令牌,或者甚至更有价值的东西。 此外,每次执行智能合同都会在公共场合发生,除此之外,源代码通常是可用的。

当然,你总是必须考虑到多少问题:您可以将智能合同与对公众开放的网络服务进行比较(因此也可以与恶意角色进行比较),甚至可以开源。 如果您仅将该杂货清单存储在该Web服务上,则可能不需要太多的关心,但如果您使用该Web服务管理您的银行帐户,则应该更加小心。

本节将列出一些陷阱和一般安全建议,但当然可以永远不会完成。 另外,请记住,即使您的智能合同代码是无错误的,编译器或平台本身也可能出现错误。 可以在已知错误列表中找到编译器的一些已知的安全相关错误的列表,它们也是机器可读的。 请注意,有一个错误赏金程序涵盖了Solidity编译器的代码生成器。

和往常一样,使用开源文档,请帮助我们扩展本节(特别是一些例子不会造成伤害)!

陷阱

私有信息和随机性

您在智能合同中使用的一切都是公开的,即使局部变量和状态变量标记private

如果您不希望矿工能够作弊,在智能合同中使用随机数是非常棘手的。

重入特性

任何来自合约(A)与另一份合约(B)的任何交互以及以太网转交给该合约的任何转让(B)。 这使得B在此交互完成之前可以回叫到A。 举一个例子,下面的代码包含一个错误(它只是一个代码段,而不是一个完整的合同):

pragma solidity ^0.4.0;

// 本合约包含错误 - 请勿使用
contract Fund {
    /// 映射合约的ether
    mapping(address => uint) shares;
    /// 提取你的份额
    function withdraw() {
        if (msg.sender.send(shares[msg.sender]))
            shares[msg.sender] = 0;
    }
}

这里的问题不是太严重,因为gas作为发送的一部分,但仍然存在弱点:Ether传输总是包括代码执行,所以收件人可能是一个回叫撤回的合同。这将让它获得多次退款,并基本上检索合同中的所有Ether。

为了避免重入,您可以使用下面进一步列出的Checks-Effects-Interactions模式:

pragma solidity ^0.4.11;

contract Fund {
    /// 映射合约的ether
    mapping(address => uint) shares;
    /// 提取你的份额
    function withdraw() {
        var share = shares[msg.sender];
        shares[msg.sender] = 0;
        msg.sender.transfer(share);
    }
}

请注意,重入不仅仅是ether传输的影响,而是对另一个合约的任何功能调用。 此外,您还必须考虑多合约情况。 被调用合约可以修改您依赖的另一个合约的状态。

gas限制和循环

没有固定次数循环的循环,例如,依赖于存储值的循环,必须仔细使用:由于gas限制,事务只能消耗一定量的gas。 由于正常操作,明确地或仅仅是循环中的迭代次数可以超过块gas限制,这可能导致完整的合约在某一点停滞。 这可能不适用于只执行从块链接读取数据的常量函数。 尽管如此,这些功能可能被其他合约称为在线操作的一部分,并将其拖延。 请在您的合约文件中明确说明这些情况。

发送和接收Ether

合同和“外部账户”目前都无法阻止某人发送它们。 合同可以做出反应并拒绝常规传输,但是有一些方法可以在不创建消息调用的情况下移动Ether。 一种方法是简单地“挖掘”合同地址,第二种方式是使用selfdestruct(x)

如果合同收到Ether(没有被调用的功能),则执行回退功能。 如果没有回退功能,则Ether将被拒绝(通过抛出异常)。 在执行回退职能时,合约只能依靠当时可用的“gas津贴”(2300gas)。 这个补贴不足以以任何方式访问存储。 为确保您的合同能够以这种方式接收Ether,请检查回退功能的gas需求(例如Remix中的“详细信息”部分)。

有一种方法可以使用addr.call.value(x)()将更多的气体转发给接收合同。 这与addr.transfer(x)基本相同,只是它转发所有剩余的气体,并打开了收件人执行更昂贵的操作的能力(它只返回故障代码,不会自动传播错误)。 这可能包括回调发送合同或者您可能没有想到的其他状态更改。 因此,它可以为诚实用户提供极大的灵活性,也可以为恶意角色扮演角色。

如果要使用address.transfer发送Ether,请注意一些细节:

1.如果收件人是合约,则会导致其回退功能被执行,从而可以回调发送合同。

2.由于呼叫深度超过1024,发送Ether可能会失败。由于呼叫者完全控制呼叫深度,因此可能会迫使传输失败; 考虑这种可能性或使用发送,并确保始终检查其返回值。 更好的是,使用收件人可以提取Ether的模式来编写合约。

3.发送以太网也可能失败,因为接收方合同的执行需要超过分配的气体量(明确地通过使用require, assert, revert, throw出或因为操作太贵) - 它“耗尽”(OOG)。 如果您使用transfersend返回值检查,这可能为收件人阻止发送合同中的进度提供了一种方法。 再次,这里的最佳做法是使用“撤回”模式而不是“发送”模式。

调用堆栈深度

外部函数调用可以随时失败,因为它们超过了1024的最大调用堆栈。在这种情况下,Solidity会引发异常。 在与您的合同交互之前,恶意代理人可能会强制调用堆栈达到高价值。

请注意,如果调用堆栈耗尽,则.send()不会引发异常,而在这种情况下返回false。 低级函数.call(),..callcode().delegatecall()的行为方式相同。

tx.origin

切勿使用tx.origin进行授权。 假设你有这样的钱包合同:

pragma solidity ^0.4.11;

// 本合约包含错误 - 请勿使用
contract TxUserWallet {
    address owner;

    function TxUserWallet() {
        owner = msg.sender;
    }

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

现在有人把你发送给这个攻击钱包的地址:

pragma solidity ^0.4.11;

interface TxUserWallet {
    function transferTo(address dest, uint amount);
}

contract TxAttackWallet {
    address owner;

    function TxAttackWallet() {
        owner = msg.sender;
    }

    function() {
        TxUserWallet(msg.sender).transferTo(owner, msg.sender.balance);
    }
}

如果您的钱包已经检查了msg.sender的授权,它将获得攻击钱包的地址,而不是所有者的地址。 但是通过检查tx.origin,它会获得启动交易的原始地址,该地址仍然是所有者地址。 攻击钱包立即耗尽所有资金。

次要细节

对于for (var i = 0; i < arrayName.length; i++) { ... }i的类型将为uint8,因为这是保存值0所需的最小类型。如果数组有更多 超过255个元素,循环将不会终止。

函数的常量关键字当前没有被编译器强制执行。 此外,它不是由EVM执行的,所以“claims”为常数的合同函数可能仍然导致状态的改变。

不占用32个字节的类型可能包含“脏高位”。 如果您访问msg.data,这是特别重要的 - 它带来可延展性风险:您可以制作一个调用函数f(uint8 x)的事务,原始字节参数为0xff000001和0x00000001。 两者都符合合同规定,两者将看起来像x一样,但是msg.data将不同,所以如果你使用keccak256(msg.data),你会得到不同的结果。

建议

限制Ether的量

限制可以存储在智能合同中的Ether(或其他令牌)数量。 如果您的源代码,编译器或平台有错误,这些资金可能会丢失。 如果你想限制你的损失,限制以太网的数量。

保持小而模块化

保持您的合约小而易于理解。 在其他合同或库中单独列出不相关的功能。 关于源代码质量的一般建议当然适用:限制局部变量的数量,函数的长度等。 记录您的功能,以便其他人可以看到您的意图,以及它是否与代码不同。

使用Checks-Effects-Interactions模式

大多数函数将首先执行一些检查(谁称为函数,是范围的参数,它们是否发送足够的以太网,该人是否具有令牌等)。 这些检查应该先做好。

作为第二步,如果所有支票通过,都应对当前合同的状态变量产生影响。 与其他合同的互动应该是任何功能的最后一步。

早期合同延迟了一些影响,并等待外部函数调用返回到非错误状态。 这通常是一个严重的错误,因为上面解释的重入问题。

请注意,对已知合同的调用也可能会导致未知合同的调用,因此总是应用此模式可能更好。

引入故障安全模式

在使系统完全分散化的同时,将删除任何中介,这可能是一个好主意,特别是对于新的代码,包括某种故障安全机制:

您可以在您的智能合同中添加一个功能,执行一些自检,例如“有任何ether泄漏?”,“令牌的总和等于合同的余额”或类似的事情。 请记住,您不能使用太多的气体,因此可能需要通过脱机计算来帮助。

如果自检失败,合同将自动切换为某种“故障安全”模式,例如,禁用大部分功能,对固定和受信任的第三方进行控制,或者将合同转换为简单的“ 给我回钱“合约。

形式化验证

使用形式验证,可以执行自动数学证明,您的源代码满足一定的正式规范。 规范仍然是正式的(就像源代码一样),但通常要简单得多。

请注意,正式验证本身只能帮助您了解您所做的(规格)与实际操作(实际执行)之间的区别。 您仍然需要检查规格是否符合您的要求,并且您不会错过任何意外的影响。

时间: 2024-09-14 07:30:22

【Solidity】注意事项的相关文章

『区块链智能合约』从零构建Ethereum智能合约到实战开发

『区块链智能合约』从零构建Ethereum智能合约到实战开发 为什么说现在学习区块链才是最好的时机? 区块链技术不只是能开发数字货币,不只是能进行ICO.当我分享一些区块链文章的时候,偶尔总会有人艾特我说,春哥,现在国家都不让炒币了,还弄个毛的区块链啊.我一般会很平静的告诉他,数字货币只是区块链落地产品类型之一,严格来讲,交易所关闭,国家不让ICO是好事,大家会发现,现在国家禁止ICO后,币圈瞬间清净多了,我觉得是好事,因为现在暴露了很多打着ICO牌子裸泳的人,只有揭开皇帝的新装,区块链技术才能

安装win7系统后需要注意的三大事项

  安装win7系统后需要注意的三大事项 1.禁止休眠 休眠过程中会导致网络也会跟着断开,而且还会占用系统盘的空间,关闭的话还可以提高运行速度的,何乐而不为呢? 2.删除旧系统备份文件 在win7系统安装完毕之后,默认情况下是会自动生成系统备份的,但是因为系统备份所占据的内存空间比较大,所以建议大家删除.在后期如果遇到问题,可以选择启动系统还原功能即可修复了. 3.虚拟内存的设置 在安装完成之后为了能够有效的提升运行速度,建议用户可以转移内置的虚拟内存,如果win7系统用户自带的内存空间较大的话

并行安装Visual Studio系统的注意事项分析

有时候出于系统兼容性的需要,开发人员可能会在操作系统上安装Visual的各个版本.如 Visual2008与2005.为什么开发人员会有这么需要呢?如原先开发人员在2005环境下开发了一个 ERP系统.现在开发人员觉得2008这个开发平台比较适合自己,就需要将这个软件移植到2008的 开发环境下.由于不同的版本在功能上会有所差异,为此就需要同时使用两个不同版本的开发 环境,以便于测试系统的兼容性.此时就需要在同一台计算机上同时部署多个版本的开发环境 .利用专业的术语就是说,Visual的并行安装

MySQL主从严重延迟后迁移Transfer的注意事项

MySQL-Transfer逐渐有一些其他公司的同学在使用,这里会持续更新运维上的注意事项.        背景        正常情况下,若要从原来的主从切换成Transfer 模式,只需要作如下步骤: 1.在slave相同机器上部署一个Transfer,并配置好各种remote_slave参数 2.在slave上stop slave 3.把slave的表结构dump给transfer 4.从slave中查看当前执行到master的位置 5.在transfer执行change master x

Photoshop制作广告印刷品的注意事项

  Photoshop是很多从事广告设计的网友都在使用的一款专业的图像编辑软件,不过,不少网友表示用Photoshop设置出来的图像,打印成成品的时候,颜色失真很严重.很模糊,这是怎么回事呢?其实,这与Photoshop的颜色模式有关,也跟Photoshop的分辨率有关.下面,小编就给大家介绍使用使用Photoshop制作广告印刷品的时候的注意事项! Photoshop 1.确定图片精度为300dpi/像素/英寸; 2.确定图片模式为CMYK模式; 3.确定实底(如纯黄色.纯黑色等)无其它杂色;

部署万兆以太网的十个注意事项

IEEE万兆以太网(10GbE)的标准--IEEE 802.3ae-2002标准--在八年前就已经核准发布.与此同时,大型企业开始满怀信心地在他们企业的骨干.数据中心和服务器群组部署万兆以太网来支持高带宽.任务关键型的应用.     多年以来,万兆以太网技术的改进.价格的下降和性能的优势已经使它的应用越出了企业的数据中心并延伸到中型的网络市场.带宽需求的增加和企业应用的增长都促进了万兆以太网更广泛的部署.     本文列出了实现一个可靠.具性价比和方便易用的万兆以太网部署的十个注意事项.    

php引用(&amp;amp;)详解及注意事项

PHP的引用(就是在变量或函数或对象或对象方法 等前面加上&符号) 在PHP 中引用的意思是:不同的名字访问同一个变量内容. 与C语言中的指针是有差别的.C语言中的指针里面存储的是变量的内容,在内存中存放的地址. 1.变量的引用 PHP 的引用允许你用两个变量来指向同一个内容. <? $a = "ABC"; $b = &$a; echo $a; //这里输出:ABC echo $b; //这里输出:ABC $b = "EFG"; echo $a

数据库安全应用 使用MySQL的23个注意事项

使用MySQL,安全问题不能不注意.以下是MySQL提示的23个注意事项: 1.如果客户端和服务器端的连接需要跨越并通过不可信任的网络,那么就需要使用SSH隧道来加密该连接的通信. 2.用set password语句来修改用户的密码,三个步骤,先"mysql -u root"登陆数据库系统,然后"mysql> update mysql.user set password=password('newpwd')",最后执行"flush privilege

MySQL数据库的23个特别注意的安全事项

使用MySQL数据库,安全问题很不容忽视,要想安全使用MySQL数据库,就要认真理解下面讲解的关于使用MySQL数据库要特别注意的23个安全事项: 1.如果客户端和服务器端的连接需要跨越并通过不可信任的网络,那么就需要使用SSH隧道来加密该连接的通信. 2.用set password语句来修改用户的密码,三个步骤,先"mysql -u root"登陆数据库系统,然后"mysql> update mysql.user set password=password('newp