主页 > 苹果下载imtoken教程 > 摩云一区块链技术分析二期-以太坊智能合约漏洞分析总结
摩云一区块链技术分析二期-以太坊智能合约漏洞分析总结
概括
本文将与大家分享以太坊智能合约中常见的三个安全漏洞(交易顺序依赖漏洞、伪随机数漏洞、重入漏洞),并结合代码示例分析漏洞产生的原因。 我希望你在写合同时能避免它们。 这些漏洞。
智能合约介绍
智能合约是存储在区块链上的一段代码,创建者通过“创建”交易将合约部署在以太坊区块链上。 每个合约都有一个合约地址,通过它我们可以找到合约。 合约的源代码不在区块链上,只有编译后的字节码存储在区块链上以太坊的标准协议,可以被以太坊虚拟机EVM解释执行。 我们通过向智能合约所在的地址发送交易来调用智能合约。
下面是用solidity编写的智能合约代码。 代码的一般功能是创建者设置一个数学问题diff和一个奖励reward。 最先解决这道数学题的参赛者将获得奖励。 奖励值是reward eth。 合约创建者所有者通过“创建”交易在区块链上安排合约。 当合约被区块链接受时,所有矿工都会自动将区块链更新到一个新的状态,并将新合约添加到区块链中。 区块链大致分为3步: 1. 准备一个唯一的合约地址; 2、为合约申请私有存储空间,执行合约构造函数,完成合约初始化; 3.设置合约的对外接口函数(),然后通过所有合约交易都使用这个接口作为入口函数(图1,15行函数)。
(图1)
调用合约的任何交易数据都封装在 msg 变量中。 例如,合约创建者的所有者可以发起交易来更新奖励。 所有者向合约发送一个新的 eth (msg.value)。 合约收到后,会更新之前的eth奖励金额,返还给所有者,奖励更改为新的值。 同样,参与者也可以发起交易来提交对合约的回答。 如果答案正确,奖励将发送给参与者。
气体系统
以太坊的智能合约由分布式计算执行,参与分布式计算的是分布在世界各地的矿工。 为了鼓励矿工执行合约逻辑,以太坊设计了一种支付计算机制,这就是gas系统。 矿工在执行合约时,每一步的计算都有明确的标注。 下图是网上找的一些基本操作消耗的gas。
如果合约逻辑复杂,gas 会消耗更多。 交易的发起方需要向矿工支付一定数量的gas。 交易发起方需要在交易发生前设置gaslimit。 gaslimit 表示参与者希望在此交易中花费的最大 gas 量。 如果实际消耗的gas小于gaslimit,则交易成功,剩余的gas将退还给交易发起者。 如果实际消耗的gas大于gaslimit,交易将失败,gas将被消耗掉,不予返还。 gas 目前的价格是 4.2Gwei。 如果交易者想提高交易处理速度,可以提高gas的单价(gasprice)。 矿工在处理交易时更愿意处理 gasprice 更高的交易。
智能合约安全漏洞
1 事务顺序依赖漏洞(Transaction-Ordering Dependence)
我们知道,区块链是由很多区块组成的链表,区块中实际存储的是一笔交易数据。 当矿工执行并将这些交易打包成块时,打包的顺序由矿工决定。 假设有两笔交易 ti 和 tj 需要处理,它们都来自同一个合约,几乎同时产生。 矿工可以选择先执行ti,也可以选择先执行tj。 这意味着ti和tj的执行顺序是不确定的。 有些合约依赖于交易顺序,不确定的交易顺序对合约的执行结果影响很大。 我们认为存在该问题的合约存在交易顺序依赖漏洞。
无害场景:
事实上,图 1 所示的 Puzzle 合约存在交易序列依赖漏洞。 我们假设合约发布了两笔交易 T1 和 T2,这两笔交易几乎同时发生。 T1是所有者更新奖励的交易,T2是参与者提交正确答案的交易。 这两笔交易很可能会打包在一个区块中。 如果T1先于T2执行以太坊的标准协议,则参与者将获得更新后的奖励; 如果 T2 在 T1 之前执行,则参与者将在更新之前获得奖励。 这实际上非常类似于多线程条件漏洞。
有害场景:
无害的情况只是偶尔发生,因为所有者无法知道参与者的正确答案何时提交。 但是恶意所有者可以利用合约的交易顺序依赖性来获利。 恶意所有者可以持续监控网络以查看是否有任何参与者提交了正确答案。 这里有一个背景知识,大家应该都知道,从这笔交易发生到这笔交易被矿工打包成一个区块,大约需要12秒的时间。 恶意拥有者在得到参与者提交的答案的交易后,也立即发起修改奖励的交易,将奖励更改为一个很小的值。 因为这两个交易的打包顺序是不确定的,修改奖励的交易可能会在提交答案的交易之前被打包,所以参与者得到的奖励很少,所有者花费少量的钱来欺骗参与者帮助他作品。 Owner 还可以增加和修改奖励交易的 gas 值,因此 Owner 的交易很可能在参与者之前被矿工打包。
2 伪随机数漏洞
以太坊官方没有给开发者提供生成随机数的接口,需要开发者自己实现随机数。 开发者一般的设计思路是选择一个种子,然后根据种子进行一些复杂的线性运算,得到一个伪随机数。 但很多情况下,开发者选择的种子可以被攻击者获取,这就导致生成的随机数可以被攻击者准确预测。 我们将存在此问题的合约称为伪随机数漏洞。
近期,多款彩票博彩区块链游戏被曝存在伪随机数漏洞(Luckyos、EOS.WIN、DEOSBET、FairDice、EosRoyale、EOSDice、FFGame),黑客在开奖前或下注时就已经知道开奖结果,所以黑客每次都能赢得奖励。 下面以存在伪随机数漏洞的合约为例进行漏洞分析。 本合约是一款猜随机数赢取奖励的游戏。 下面是随机数生成部分的代码:
(图二)
当矿工挖出一个区块时,他必须为这个区块设置时间戳值。 一般情况下,这个值设置为矿工挖出区块的时间。 但这不是绝对的,矿工可以在误差900s左右的范围内改变这个值,那么矿工就可以在很大程度上影响上述随机数的种子。
除了时间戳,还有其他的区块属性值作为随机数种子,例如,
(1)block.coinbase表示当前区块的矿工地址
(2)block.difficulty表示当前区块的挖矿难度
(3) block.gaslimit 区块内交易的最大gas消耗上限
(4)block.number表示当前区块高度
这些值是矿工在打包交易时已知的。
我们假设一个场景:假设一个矿工(或者矿工的关联方)正在玩这个游戏,他提交了自己的猜测值等待开奖。 当彩票交易发生的时候,这时候他挖出一个新的区块,想把这笔交易打包进这个区块,那么他就会在这个时候操作timestamp的值(除了timestamp,block.number和Last_Payout的值都是determined) ,从而影响合约 random() 函数的返回值,从而使你能够正确猜出结果。
3 重入漏洞
以太坊智能合约可以调用和使用其他外部合约的代码。 合约通常也处理以太币,因此以太币被发送到各种外部用户地址。 调用外部合约或向地址发送以太币的操作需要合约提交外部调用。 这些外部调用可以被攻击者劫持以强制合约执行更多代码(即通过 fallback 实现回退功能),包括回调原始合约本身。 因此,在合约代码执行过程中,将有可能“重新进入”合约,有点像编程语言中的间接递归函数调用。 在臭名昭著的 The DAO 事件中,黑客使用了这种攻击,最终导致了以太坊的硬分叉。
以下代码为存在重入漏洞的合约代码:
(图3)
上述合约代码中,withdrawBalance()函数通过call函数调用外部合约,将eth转入extractor。 但问题是外部合约代码不可控。 攻击者可以构造一个恶意合约,然后调用SendBalance合约的withdrawBalance()函数。 此时 userBalances [msg . 发件人] = 0; 这句话没有机会被执行,所以 if (!( msg . sender . call . value (userBalances [msg . sender ])())) { throw ; } 这句话还是可以转出eth的。 这种循环调用会在将 SendBalance 合约拥有的所有 eth 全部转移(或耗尽 gas)后停止,这是非常有害的。
总结:
本文分析了以太坊智能合约中危害较大的三个常见漏洞。 安全社区也提供了安全的编程方法来避免这些漏洞。例如,为了避免重入漏洞,尽量不要使用call()方法来传输交易; 为了避免伪随机数漏洞,可以引入第三方服务Oraclize获取随机数