知道创宇404区块链安全研究团队 62%的以太坊合约存在“合约设计缺陷”

上一页[1] [2]

一、 简介

在知道创宇404区块链安然钻研团队收拾输出的《知道创宇以太坊合约审计CheckList》中,把“前提竞争问题”、“轮回DoS问题”等问题统一归类为“以太坊智能合约设计缺陷问题”

“昊天塔(HaoTian)”是知道创宇404区块链安然钻研团队自力开拓的用于监控、扫描、阐发、审计区块链智能合约安然自动化平台我们使用该平台针对上述提到的《知道创宇以太坊合约审计CheckList》中“以太坊智能合约设计缺陷”类问题在全网公开的智能合约代码做了扫描阐发详见下文:

二、破绽详情

1、前提竞争

2016年11月29号,Mikhail Vladimirov和Dmitry Khovratovich公开了一篇《ERC20 API: An Attack Vector on Approve/TransferFrom Methods》,在文章中提到了一个在ERC20标准中存在的隐患问题,前提竞争

这里举一个approve函数中会呈现的对照范例的例子,approve一样平常用于授权,比如授权别人可以取走自己的若干代币,全部流程是这样的:

用户A授权用户B 100代币的额度

用户A感觉100代币的额度太高了,再次调用approve试图把额度改为50

用户B在待买卖营业处(打包前)看到了这笔买卖营业

用户B构造一笔提取100代币的买卖营业,经由过程前提竞争将这笔买卖营业打包到了改动额度之前,成功提取了100代币

用户B提议了第二次买卖营业,提取50代币,用户B成功拥有了150代币

想要理解上面这个前提竞争的道理,首先我们得对以太坊的打包买卖营业逻辑有根基熟识

https://medium.com/blockchannel/life-cycle-of-an-ethereum-transaction-e5c66bae0f6e

简单来说便是

只有当买卖营业被打包进区块时,他才是弗成变动的

区块会优先打包gasprice更高的买卖营业

以是当用户B在待打包处看到改动的买卖营业时,可以经由过程构造更高gasprice的买卖营业来竞争,将这笔买卖营业打包到改动买卖营业之前,就孕育发生了问题

以下代码就存在前提竞争的问题

function approve(address _spender, uint256 _value) public returns (bool success){

allowance[msg.sender][_spender] = _value;

return true

2、轮回DoS问题

在以太坊代码中,轮回是一种很常见的布局,但因为以太坊智能合约的特殊性,在轮回也有很多必要分外留意的点, 存在潜在的合约问题与安然隐患

1) 轮回耗损问题

在以太坊中,每一笔买卖营业都邑耗损必然的gas,而买卖营业的繁杂度越高,则该买卖营业的gasprice越高而在区块链上,每个区块又有最大年夜gas耗损值限定,且在矿工最优化收益规划中,假如一个买卖营业的gas耗损过大年夜,就会倾向性把这个买卖营业扫除在区块外,从而导致买卖营业掉败

以是,对付合约内的轮回次数不宜过大年夜,在轮回中的代码不宜过于繁杂

struct Payee {

address addr;

uint256 value;

}

Payee payees[];

uint256 nextPayeeIndex;

function payOut() {

uint256 i = nextPayeeIndex;

while (i200000) {

payees[i].addr.send(payees[i].value);

i++;

}

nextPayeeIndex = i;

}

假如上述代码地址列表过长,就有可能导致买卖营业掉败

2018年7月23日,Seebug Paper颁发的《首个区块链 token 的自动化薅羊毛进击阐发》中进击合约就提到了这种gas优化要领

2) 轮回安然问题

在以太坊中,应该只管即便避免轮回次数受到用户节制,进击者可能会应用过大年夜的轮回来完成Dos进击

function distribute(address[] addresses) onlyOwner {

for (uint i = 0; i

当进击者经由过程赓续添加address列表长度,来迫使该函数履行轮回次数过多,导致合约无法正常掩护,函数无法履行

2016年,GovernMental合约代币被爆出恶意进击,导致地址列表过长无法履行,跨越1100 ETH被困在了合约中

三、破绽影响范围

应用Haotian平台智能合约审计功能可以准确扫描到该类型问题

基于Haotian平台智能合约审计功能规则,我们对全网的公开的共39548 个合约代码进行了扫描,此中共24791个合约涉及到这类问题

1、 前提竞争

截止2018年8月10日为止,我们发清楚明了22981个存在approve前提竞争的合约代码,此中15325个合约仍处于买卖营业状态,此中买卖营业量最高的10个合约环境如下:

2、 轮回DoS问题

截止2018年8月10日为止,我们发清楚明了1810个存在潜在轮回dos问题的合约代码,此中1740个合约仍处于买卖营业状态,此中买卖营业量最高的10个合约环境如下:

四、修复要领

1)前提竞争

关于这个问题的修复要领评论争论很多,因为这属于底层特点的问题,以是很难在智能合约层面做办理,在代码层面,我们建议在approve函数中加入

require((_value == 0) || (allowance[msg.sender][_spender] == 0));

[1] [2]下一页

将这个前提加入,在每次改动权限时,将额度改动为0,再将额度改为对应值

在这种环境下,合约治理者可以经由过程日志或其他手段来判断是否有前提竞争发生,从风控的角度警觉合约治理者留意该问题的发生典型代码如下:

function approve(address _spender, uint256 _value) isRunning validAddress returns (bool success) {

require(_value == 0 || allowance[msg.sender][_spender] == 0);

allowance[msg.sender][_spender] = _value;

Approval(msg.sender, _spender, _value);

return true;

}

2)轮回DoS问题

在面临轮回DoS问题孕育发生的场景中,最为常见的便是向多个用户转账这个功能

这里保举代码中只管即便避免用户可以节制轮回深度,假如无法避免的话,只管即便应用类似withdrawFunds这种函数,轮回中只分发用户提币的权限,让用户来提取属于自己的代币,经由过程这种操作可以大年夜幅度节省花费的gas开支,也可以必然程度避免可能导致的问题代码如下所示:

function distribute(address[] addresses) onlyOwner {

for (uint i = 0; i

五、一些思虑

在阐发了许多智能合约已有的破绽以及合约今后,我发明有一类问题对照特殊,这些问题的出生根滥觞基本因都是由于以太坊智能合约本身的设计缺陷,再加上开拓者对此没有清晰的熟识,导致了合约本身的一些隐患

文章中提到的前提竞争是个对照特殊的问题,这里的前提竞争涉及到了智能合约底层实现逻辑,本身打包逻辑存在前提竞争,我们无法在代码层面避免这个问题,但对付开拓者来说,比起无缘无真个由于该问题损掉代币来说,更紧张的是合约治理者可以监控到每一笔买卖营业的结果,以是我们加入置0的操作来提醒合约治理者、代币持有者该问题,只管即便避免这样的操作发生

而轮回Dos问题便是一个针对开拓者的问题,每一次操作便是一次买卖营业,每次买卖营业就要花费gas,买卖营业越繁杂花费的gas越多,而在区块链上,每个区块又有最大年夜gas耗损值限定,且在矿工最优化收益规划中,假如一个买卖营业的gas耗损过大年夜,就会倾向性把这个买卖营业扫除在区块外,从而导致买卖营业掉败这也就直接导致了在买卖营业中,我们必要尽可能的优化gas花费,避免买卖营业掉败

我们在对全网公开的合约代码进行扫描和监控时轻易发明,有很大年夜一批开拓职员并没有留意到这些问题,此中前提竞争问题以致影响广泛,有跨越一半以上的公开代码都受到影响

这里我们建议所有的开拓者从新核阅自己的合约代码,反省是否存在设计缺陷问题,避免不需要的麻烦以及安然问题

赞(0) 打赏
分享到: 更多 (0)
免责申明:本站所有资料均来自于网络,版权归原创者所有!本站不提供任何保证,不保证真实性,并不承担任何法律责任

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

阿里云优惠网 更专业 更优惠

阿里云优惠券阿里云大礼包