首页 手机兼职平台区块链正文

DeFi 安全事情为何频发?整理以太坊智能合约常见缝隙

网赚之家 区块链 2020-11-24 12:30:07 7667 0

Ownbit

DeFi

概述

比较于比特币而言,以太坊更易产生安全事故。这首要是由于以太坊虚拟机是图灵齐备的,以太坊可完结函数间彼此调用、嵌套调用,智能合约间彼此调用等各种杂乱逻辑。而比特币只完结了根据栈的非图灵齐备的虚拟机,并只能经过操作码进行入栈和出栈操作。别的比特币也没有杂乱的 DApp 运用,所以逻辑上简略,故而没有太多空间引发安全缝隙。

以太坊上各种 DApp 杂乱的智能合约逻辑是引发安全缝隙的主因。以太坊智能合约的安全缝隙首要能够分为逻辑问题合约代码问题两种。

逻辑问题

最近频频的「闪电贷」进犯是一个典型的逻辑问题引起的安全缝隙。在各种闪电贷进犯中你能够看到明晰的逻辑问题。进犯者只需制造出两个体系之间的价格差,便能经过闪电贷进犯获利。

闪电贷进犯的逻辑细节咱们能够阅览之前一篇专门讲闪电贷的文章:「造富神器」闪电贷。本文首要论述合约代码问题

合约代码问题

咱们知道,简直略微杂乱一点的代码都或多或少地存在问题(bug)。了解呈现问题的原因,而且概括问题类别能够协助咱们更好地防备它们。下面是 Ownbit 钱包团队收拾的关于以太坊智能合约安全最简单呈现问题的点。

重入(Reentrancy)

这是排名榜首的问题。所谓「重入」便是一个办法被屡次循环调用。而这通常是合约开发者所意想不到的。例如一个取款合约:

function withdrawEther() public {
    uint amount = userBalances[msg.sender];
    (bool success, ) = msg.sender.call.value(amount)(""); // 这儿重入
    require(success);
    userBalances[msg.sender] = 0;
}   

这是一段很简略的取款合约,让用户取走他的 ETH 余额。开发者并没有认识到这段代码或许会被重入。办法是:只需调用者是一个合约账户,那么 msg.sender.call 将默许调用该合约账户的 fallback 函数。进犯者只需要在其 fallback 函数再次调用 withdrawEther 就能够源源不断地取走 ETH。

产生在 2016 年 6 月,闻名的 The DAO 进犯,然后导致了 ETC 分叉的事情,便是经过相同的办法施行进犯的。从过后看来,这仅仅一个小小的程序问题(却形成了如此严峻的结果)。要修正这个问题也十分简单,只需要将两行代码互换次序即可:

 userBalances[msg.sender] = 0;
 (bool success, ) = msg.sender.call.value(amount)(""); 

让你的买卖不打包

以太坊区块的打包机制是依照给予的矿工费(GasPrice)进行优先打包,而且每个区块有总 GasLimit 的约束(目前为每区块 1200 万 Gas)。所以进犯者能够制造出若干运用 GasLimit 十分大,而且 GasPrice 给得十分高的买卖,让它们优先占满区块,然后让方针买卖无法被打包。

所以,在编写合约逻辑时,不能假定你的买卖会在有限时间内被打包,不然就简单遭到此类进犯。闻名的「Fomo3D」事情便是用了这样的进犯办法

Fomo3D 游戏规则是奖赏最终一个购得某个产品的人。每次产品被买入将重置该产品的定时器,假如在定时器到达 0 之前没有其他购买者,则你将取得体系的奖赏。进犯者在 Fomo3D 中买入产品,然后一起发送许多占用区块的进犯买卖,以至于在接下来的 13 个区块内,其他购买者的买卖无法被打包。这时定时器到达 0,并认为无其他购买者。进犯者便取得了奖赏,完结了进犯。

过错运用 tx.origin

假如你发现一个合约运用了 tx.origin,那么能够留神一下此处或许存在的缝隙。在大部分情况下,咱们应该运用 msg.sender 来代替 tx.origin,由于运用 tx.origin 简单引发安全缝隙。

许多时分,合约开发人员会假定 msg.sender 和 tx.origin 是持平的,但其实不是。例如:用户 A 调用 合约 B,而合约 B 进一步调用 合约 C,那么在合约 B 和 C 中 tx.origin 都将是 A,而 msg.sender 则一个是 A,一个是 B。

一般进犯者会诱惑 A 调用一个诱导合约 B,而 B 再去调用由 A 布置的方针合约 C,由于 合约 C 过错地运用了 tx.origin,合约 B 能够经过传递过来的 tx.origin 取得对 合约 C 的控制权,然后完结进犯。

溢出进犯

智能合约里的数据是或许溢出的,例如:uint256,你觉得很大:2^256。它确实很大,但仍然能够溢出。例如一个合约答应对一个数据进行加减,进犯能够经过对这个数据进行精心策划的调用,让其经过溢出到达答应履行某些逻辑的意图,然后完结进犯。

fallback 能够 revert

fallback 是能够 revert 的,便是说,你假如向对方搬运 ether,对方能够让你总是不成功。

例如你编写一段合约,而且依赖于你成功向某个地址搬运 ether,那么进犯能够布置一个合约,将其 fallback 写成 revert 来让你来的调用总是失利:

function () public payable {
   revert () ; 
}

selfdestruct 能够界说恣意受益者,而不会调用 fallback

当你认为能够经过 revert 进行阻挠所有人向你付款 ether 时,你或许又错了。进犯者经过创立一个合约,而且然后毁掉这个合约。毁掉合约以太坊将交还一部分 ether 作为鼓舞,而这个交还能够指定恣意受益者,而对方的 fallback 函数不会被调用。

这便是说,开发者要认识到你没有办法彻底阻挠他人向你的合约账户搬运 ether。

未正确运用 delegatecall

在运用 delegatecall 时,要注意上下文(即 msg.sender 等)的改变。用 call 进行合约调用时,上下文被切换至被调用合约。而用 delegatecall 进行合约调用时,上下文仍然在本合约。

delegatecall 和 call 不同的调用上下文也是合约安全缝隙较常呈现的当地。

不同办法传气不一样

当咱们进行 ether 搬运时,不同的办法传气(Gas)不一样。运用 send() 和 transfer() 传递气仅为 2300,而运用 call.value()() 则将剩下的气悉数传递。因而,最新的安全标准是主张运用 call 而不是 send 或许 transfer 进行 ether 搬运。

假如你发现一个合约仍是运用 send 或许 transfer,那么你能够制造出方针合约,让其搬运 Out of Gas。

结语

以上这些点是合约代码最常呈现问题的点。每个过错的原因都比较原子化,了解相应的原理能够协助咱们有效地防止这些问题。当合约逻辑杂乱时,必定会有愈加杂乱、躲藏得更深的逻辑问题,这时,这些原子点的查看仍然能够协助咱们找到它们。

以太坊智能合约的安全问题首要是由于其「过于灵敏」引起的。灵敏性和安全性好像天平的两头。以太坊挑选了灵敏性,某种程度上便把安全性的潜在危险留给了商场。

DeFi线

mp.weixin.qq.com

版权声明

本文仅代表作者观点,不代表网赚之家本站立场。
本文系作者授权发表,未经许可,不得转载。

评论