您好,欢迎您来到国盈网!
官网首页 小额贷款 购房贷款 抵押贷款 银行贷款 贷款平台 贷款知识 区块链

国盈网 > 区块链 > 智能合约审计是什么意思,智能合约安全隐患有哪些

智能合约审计是什么意思,智能合约安全隐患有哪些

区块链 岑岑 本站原创

背景概述

在上一篇文章中,我们了解了隐藏在合同中的恶意代码。这一次,我们学习了一种非常常见的攻击技术——抢占。

先例知识

说到竞跳,首先想到的一定是田径比赛。在田径比赛中,所有选手的身体素质都差不多,起跑越早,获得第一名的概率越大。你是怎么在以太坊逃脱的?

想要理解先发制人的攻击,首先要了解以太坊的交易流程。我们通过下面的发送交易流程图来了解一下以太坊最后一笔交易的流程:

可以看出,图中的一笔交易,从签约到被打包,会经历七个阶段:

1.使用私钥对交易内容进行签名;

2.选择气价;;

3.发送已签名的交易;

4.事务在节点间广播;

5.交易进入交易池;

6.矿商以高气价进行交易;

7.矿工打包,交易和封锁。

交易发出后,会被扔进交易池,等着被矿工打包。矿商从交易池中取出交易,进行打包和封锁。根据Eherscan的数据,当前区块的天然气限制在3000万左右,这是一个动态调整的值。以一个21000气的基本交易计算,目前一个以太坊区块大约可以容纳1428笔交易。因此,当交易池中的交易量较大时,会有很多交易无法立即打包,留在池中等待。问题来了。交易池中有如此多的交易。矿工应该先打包谁的事务?

矿工节点可以自己设置参数,但是大部分矿工都是按照手续费排序的。收费高的会先打包出来,收费低的需要等到收费高的交易都打包好了才能打包。当然,有源源不断的交易进入交易池。无论交易什么时候进入交易池,收费高的永远会先打包,收费低的可能永远不会打包。

那么手续费是怎么来的呢?

我们先来看以太坊手续费的计算公式:

Tx费=用气*气价。

用的气是系统计算出来的,气价可以自定义,所以最后的手续费要看气价定多少。

例如:

比如气价设为10 GWEI,用气为21000(卫是以太坊的最小单位,1卫= 10^-18以太,GWEI为1G卫,1g卫= 10-9以太)。因此,根据手续费计算公式,手续费可以计算如下:

10 GWEI(燃油单价)* 21000(油耗)= 0.00021乙醚(手续费)

在合同中,我们经常看到通话功能会设置气限。让我们来看看它是什么:

气限可以从字面上理解,就是气限的意思。它设置为显示您愿意在这笔交易中花费多少汽油。当交易涉及复杂的合同交互时,您不确定实际使用的气体。可以设置气限,包装时只收取实际使用的气作为手续费,多出来的气返还。当然,如果实际用气>:Gas Limit会发生缺气,导致事务回滚。

当然,在实际交易中选择合适的气价也很重要。我们可以在ETH加油站上看到气价的实时打包速度:

从上图可以看出,目前最快打包速度对应的气价是2,我们只需要设置气价为>;= 2的值可以尽快打包。

嗯,相信大家都能猜到先发制人的攻击模式,就是在发送交易的时候,把气价抬高,让矿工先打包。让我们通过一个契约代码来了解如何完成攻击。

合同示例

//spdx-license-identifier:MIT pragma solidity ^0.8.17;contract find this hash { bytes 32 public constant hash = 0x 564 ccaf 7594d 66 B1 eaaea 24 Fe 01 f 0585 BF 52 ee 70852 af 4 EAC 0 cc 4b 04711 cd0e 2;constructor()payable { } function solve(string memory solution)public { require(hash = = keccak 256(ABI . encodepacked(solution)),“答案不正确”);(bool sent,)= msg . sender . call { value:10 ether }(" ");要求(已发送,“发送乙醚失败”);}}

攻击分析

通过契约代码我们可以看到,FindThisHash契约的部署者给出了一个Hash值,任何人都可以通过solve()提交答案,只要解决方案的hash值与部署者相同,就可以获得10个以太奖励。我们排除了部署者自己能拿到奖励的可能性。

让我们邀请我们的老朋友Eve(攻击者)来看看他是如何利用先发制人的攻击拿走本该属于Bob(受害者)的奖励的:

1.Alice(契约部署者)使用10 Ether部署FindThisHash契约;

2.Bob找到其哈希值是目标哈希值的正确字符串;

3.鲍勃打电话给solve(& # 8220;以太坊& # 8221;)并将气价设置为15 Gwei;

4.Eve在监控交易池,等待有人提交正确答案;

5.Eve看到Bob发送的交易,设置比Bob高的气价(100 Gwei),调用solve(& # 8220;以太坊& # 8221;);

6.Eve的交易在Bob的交易之前被矿工打包;

7.夏娃赢得了10个以太币的奖励。

Eve在这里的一系列操作是标准的先发制人攻击,所以我们可以在这里定义邰方的先发制人攻击:先发制人攻击是通过设置更高的气价来影响交易打包的顺序,从而完成攻击。

那么如何避免这种攻击呢?

维修建议

在撰写合同时,您可以使用提交-揭示方案:

https://medium . com/swlh/exploring-commit-reveal-schemes-on-ether eum-C4 ff 5a 777 db 8

以下修复代码在Solidity by Example中提供。让我们看看它能否完美防御先发制人的攻击。

//spdx-license-identifier:MIT pragma solidity ^0.8.17;导入“github . com/open zeppelin/open zeppelin-contracts/blob/release-v 4.5/contracts/utils/strings . sol”;协定SecuredFindThisHash { // Struct用于存储提交详细信息Struct Commit { bytes 32 solution hash;委托时间;布尔透露;} //需要由es32 public hash求解的hash = 0x 564 ccaf 7594d 66 B1 eaaea 24 Fe 01 f 0585 BF 52 ee 70852 af 4 EAC 0 cc 4b 04711 cd0e 2;//winner地址public winner的地址;//要奖励的价格uint公开奖励;//游戏bool公共结束的状态;//使用地址映射存储提交详细信息的映射(address = & gtCommit)提交;//修改器检查游戏是否活动修改器gameActive() { require(!结束了,“已经结束了”);_;}构造函数()应付款{ reward = msg.value} /* Commit函数存储使用keccak256(小写地址+解+密)计算的散列。用户只能提交一次,如果游戏是活跃的。*/function Commit solution(bytes 32 _ solution hash)public game active { Commit storage Commit = commits[msg . sender];require(commit.commitTime == 0,“已经提交”);commit . solution hash = _ solution hash;commit . commit time = block . timestamp;commit . discovered = false;} /*函数来获取提交细节。它返回一个元组(solutionHash,commitTime,reveal status);用户只有在游戏处于活动状态并且提交了solution hash */function getmy solution()public view game active returns(bytes 32,uint,bool){ Commit storage Commit = commits[msg . sender];require(commit.commitTime!= 0,“尚未提交”);return (commit.solutionHash,commit.commitTime,commit . discovered);} /*函数显示提交并获得奖励。只有当游戏是活跃的,并且他们在这个区块之前已经提交了一个解决方案灰,并且还没有显示,用户才能获得显示解决方案。它生成一个keccak 256(msg . sender+solution+secret ),并使用之前提交的哈希对其进行检查。领先者将无法通过此检查,因为消息发送者不同。然后使用keccak256(解决方案)检查实际解决方案,如果解决方案匹配,则宣布获胜者,游戏结束并将奖励金额发送给获胜者。*/function reveal solution(string memory _ solution,string memory _ secret)public game active { Commit storage Commit = commits[msg . sender];require(commit.commitTime!= 0,“尚未提交”);require(commit . commit time & lt;block.timestamp,“不能在同一个块中显示”);要求(!commit . discovered,“已经提交并公开”);bytes 32 solution hash = ke ccak 256(ABI . encode packed(strings . tohexstring(msg . sender),_solution,_ secret));require(solution Hash = = commit . solution Hash," Hash不匹配");require(keccak 256(ABI . encode packed(_ solution))= = hash,“回答不正确”);winner = msg.senderended = true(bool sent,)= payable(msg.sender)。调用{ value:reward }(" ");如果(!已发送){ winner =地址(0);ended = falserevert("发送乙醚失败。");} }}

首先我们可以看到修复代码中使用了结构Commit来记录玩家提交的信息,其中:

提交。solution hash = _ solution hash = keccak 256(玩家地址+答案+密码) 【记录玩家提交的答案哈希】

提交。提交时间=阻塞。时间戳[记录提交时间]

commit . discovered = false[记录状态]

让我们看看这个合同是如何运作的:

1.Alice使用十个以太网来部署SecuredFindThisHash契约;

2.Bob找到其哈希值是目标哈希值的正确字符串;

3.Bob计算解Hash = Keccak256 (Bob的地址+“以太坊”+Bob的秘密);

4.Bob调用commitSolution(_solutionHash)并提交刚刚计算的solution hash;

5.Bob在下一个街区调用Reveal Solution(& # 8220;以太坊& # 8221;,鲍勃& # 8217;S secret)函数,传入答案和自己的密码,获得奖励。

这里,我们来看看这个合同是如何避免先占权的。首先,在第四步中,Bob提交了三个值的hash(Bob的地址+“以太坊”+Bob的秘密),所以没有人知道Bob提交了什么。这一步还记录提交的块时间,并在第五步中首先检查revealSolution()中的块时间。这是为了防止同一区块的彩票被抢,因为调用revealSolution()时,需要明确的答案。最后,使用Bob输入的答案和密码来验证它是否与之前提交的solutionHash散列相匹配。这一步是为了防止有人不采用commitSolution()就直接调用revealSolution()。验证成功后,检查答案是否正确,最后发放奖励。

所以这个合同真的阻止了Eve完美抄袭答案?

当然不是!

这是怎么回事?我们看到唯一承诺。提交时间

所以问题是,我们如何有效地防止这种攻击?

非常简单,只需设置uint256 revealSpan的值并检查require (commit。commit solution+reveals span >;= block.timestamp,无法在此块中提交& # 8221;);这将防止伊芙抄袭答案。但在抽奖环节,依然无法阻止提交了答案的人先中奖。

此外,由于代码的严格性,提交。执行后,修复代码中的revealSolution未设置为True。虽然这不会影响什么,但还是建议在编写代码时养成良好的编码习惯,在执行完函数逻辑后将开关设置到正确的状态。

本网站声明:网站内容来源于网络。如有侵权,请联系我们,我们会及时处理。

温馨提示:注:内容来源均采集于互联网,不要轻信任何,后果自负,本站不承担任何责任。若本站收录的信息无意侵犯了贵司版权,请给我们来信(j7hr0a@163.com),我们会及时处理和回复。

原文地址"智能合约审计是什么意思,智能合约安全隐患有哪些":http://www.guoyinggangguan.com/qkl/149548.html

微信扫描二维码关注官方微信
▲长按图片识别二维码