如何审核智能合约

全面的测量指南 智能合约安全.

虽然区块链的兴起为分布式共识提供了独特的机会,但智能合约应用程序会带来独特的安全问题,这些问题在历史上曾导致数百万美元的损失,例如臭名昭​​著的 DAO攻击. 为了减轻这些风险,有必要进行 安全审核 关于智能合约。在本指南中,我们彻底详细介绍了各种智能合约攻击,以及必须采取的审核过程,以与最新发展保持一致的方式确保安全性,并从各种可信来源中汲取灵感. 

智能合约审核从根本上与常规代码审核相同,后者是在对代码进行公开部署之前,会认真研究代码以发现安全漏洞和漏洞。这就像在向公众开放之前测试桥梁一样。在这两种情况下,制造商均应对其产品的安全性负责。由于区块链本质上是默克尔树的复制,仅附加链接的“列表”(因此是不可变的),并且智能合约是自执行的,因此在启动之前查找代码中的任何漏洞至关重要.

如何审核智能合约

 有哪些类型的智能合约攻击?

本节讨论了您应该注意的已知攻击,以及可以在审核中发现此类攻击的特定步骤。.

比赛条件 是一般系统的行为,其中事件未按预期顺序发生。在智能合约中,竞价条件可能是由于调用接管控制流程的外部合约而产生的.

再入 描述了竞态条件的一种版本,其中在第一次函数调用完成之前重复调用某些函数。例如,DAO攻击错误之一是由不同的功能调用以意外方式交互导致的。关键解决方案是阻止并发调用在某些功能中发生,尤其是仔细检查外部调用.

带有重入错误的合同示例:

合同重入漏洞{

函数withdraw(){

uint transferAmount = 10醚;

如果(!msg.sender.call.value(transferAmount)())抛出;

}

function deposit()payable {} //使合同可付款并发送以太币

}

上方,红色突出显示的行是外部呼叫,通常应避免。函数withdraw()将10个以太转移到msg.sender中。到目前为止,一切都很好。但是,接收方可以使用递归发送漏洞多次调用该函数,如下所示.

假设上述合同位于ReentrancyVulnerability.sol文件中,并且攻击者利用外部调用创建了具有Hacker合同的Hacker.sol文件。此类合同可用于“笔测”潜在的重入漏洞:

合同黑客{

可重入漏洞r;

公众计数;

事件LogFallback(uint c,uint余额);

功能Attacker(地址易受攻击){

r =可重入漏洞(易受攻击);

}

功能Attack(){

r.withdraw();

}

功能()应付款项{

数++;

LogFallback(count,this.balance);

如果(计数 < 10){

r.withdraw();

}

}

在Hacker.sol中,定义了两个主要功能(除了重命名功能)。第一个是作为payable()的提取函数,调用ReentrancyVulnerabilitycontract withdraw()方法,将10以太币发送给Hacker,触发第二个函数:function()payable {},这是一个后备函数(用于捕获过多的以太币) ).

事件LogFallback(uint v,uint balance);定义,每当调用上面定义的后备功能时触发。此事件通过带有计数器的if语句运行,以充当循环,该循环在10次调用时停止该函数以防止以太返回。最后,再次调用Hacker的withdraw()方法。这是可能的,因为在payable()中原始的withdraw()方法完成之前,再次调用withdraw(),直到最后满足该语句并满足反条件为止.

重入是问题的征兆,而不是问题的根源,因此请确保分析使用外部函数的位置,而不是尝试直接停止某个函数的重入。这意味着在调用外部功能之前完成所有内部工作.

总结:尽量减少外部代码或以其他方式完成所有内部工作,然后再进行外部呼叫.

跨功能比赛条件 用相同的解决方案描述了两个共享相同状态的功能的类似攻击。一个示例是攻击者在用户余额设置为0之前或尽管攻击者已收到提款的情况下从外部调用transfer()

函数传递(地址至,单位数量){

转移发生在这里

}

函数withdrawBalance()公共{

uint amountToWithdraw = userBalances [msg.sender];

require(msg.sender.call.value(amountToWithdraw)());

userBalances [msg.sender] = 0;

}

在上述代码中,黑客可以在执行withdrawBalance()中的红线时或在进行外部调用时调用transfer()。如您所见,userBalance之后仅设置为0,因此尽管已提款,但黑客仍可能转移令牌.

交易订单依存关系(TOD)/前端运行 这是另一个竞争条件,但这一次是在一个区块内对交易订单进行操作的情况下。这是关于短时间将事务置于内存池中。前端运行允许一个用户从操纵的交易订单中受益,而另一位用户则为此付出了代价.

  • 一种可能允许“正面跑步”的条件是 时间戳依赖性, 因此,您必须仔细检查时间戳记的用法,尤其是在交易时间在财务上很重要的情况下(例如在投注合同中)。以太坊时间戳与同步的全球时钟断开连接,矿工可以利用这种差异.
  • 另一个条件是 整数溢出和下溢, 从而将达到最大圆的uint值设置为零或将小于零的uint值设置为其最大值。整数上溢和下溢可以通过诸如 秘银.

        

上溢和下溢的代码示例非常简单:

uint public c = a + b;

然后,攻击者可能会为下溢减去或为上溢添加:

函数下溢()公共{

c- = 2 ** 256-1;

}

函数overflow()public {

c + = 2 ** 256-1;

}

通过强制将以太币发送到合同的能力来实现另一种形式的攻击,以确保逻辑中不会尝试将资金限制在合同上,因为这种攻击会破坏该逻辑.

具有以下逻辑的任何代码都是上述漏洞:

要求(此平衡 > 0); //注意0可以是任何数字

为了防止在您正在分析的代码上成功发动此类攻击,审核过程应采用工程方法–具有理论和实践背景的严格验证以及工具应用.

 全面智能合约审核的步骤

以下审核过程将发现导致上述攻击的漏洞以及其他错误和安全问题,该审核过程的灵感来自于 ConsenSys最佳做法, 这 HashEx审核框架, 以及公共审计以创建更全面的结构:

     0.确保通过已部署的智能合约2完成审计:  

           审核应针对候选发布者(RC)或最终的Smart

           公开发布之前的合同阶段,因为这是最接近最终用户的阶段

           产品.

  1. 提供法律免责声明:请注意,审核的目的是促进基于安全原则的讨论,而不是提供任何保证.

例如:“此审核中显示的信息仅用于一般讨论目的,并不旨在为任何个人或实体提供法律安全保证。”

  1. 解释你是谁:说明您在该领域的权威,或为什么可以信任您进行严格的分析,然后通过强大的审核对其进行备份.
  2. 说明您的审核流程:从安全的角度概述正在审核的智能合约以及将使用的流程.
  3. 进行攻击漏洞测试:分析以上记录的任何相关攻击是否可以针对合同成功进行.
  4. 发现的详细漏洞和问题:在此步骤中,讨论关键的中级和低严重性漏洞以及修复建议。可能有些区域不是立即脆弱的,而是潜在的关注点-也请注意这些区域.
  5. 分析合同复杂性:复杂性会增加发生错误的可能性,因此请注意复杂的合同逻辑,未模块化的代码,专有工具和代码以及性能超过清晰度。这些都不一定是危险信号,但应尽可能避免.
  6. 分析故障准备:如果发生错误(例如错误或漏洞),合同将如何响应?检查合同是否暂停,风险资金是否得到管理.
  7. 分析代码货币:所有的库和工具是否都已更新为最新版本?最新工具版本可能附带漏洞修补程序,因此使用较旧版本是不必要且易于预防的风险.
  8. 重用与重复代码分析注意:先前部署的,经过安全验证的合同中的重复代码不需要严格的分析。但是,必须仔细审查未经审核的重用代码,并且如果有经过良好测试和先前部署的版本,则不应使用.
  9.  分析外部通话
  1. 是否避免了外部呼叫后的状态更改? 外部呼叫可能会操纵控制流程,因此请确保先完成所有内部呼叫.
  2. 是否标记了不可信的合同? 应该清楚地标记外部合同,以表明代码交互可能不安全。这包括命名约定,例如UntrustedSender相对于Sender.
  3. 是否正确处理了外部呼叫中的错误? 如果遇到异常,合同调用将自动传播抛出,并且如果不处理这种可能性(通过检查返回值),合同将失败.
  4. 外部通话是否有利于推拉? 确保将外部呼叫隔离到自己的事务中,以最大程度地减少外部呼叫失败的后果.
  1.  初始余额分析:代码是否做出任何假设,即合同将从零余额开始?在创建合同之前,合同地址可能会收到wei,因此不应有初始余额假设.
  2.  分析链上数据的安全性:确保某些链上数据的出现时间对于合同功能而言不是至关重要的,因为此数据是公开的,并且错误的订单可能使一方胜于另一方(例如在剪刀石头布游戏中).
  3.  分析N方合同:如果参与者放弃并不返回,可以吗?必须考虑这种可能性.
  4.  特定于固体
  1. 强制不变式? 断言失败会触发断言保护。处理不变量时应使用assert(),例如assert(this.balance >= totalSupply);
  2. 是否进行整数除法? 简而言之,所有整数除法都将四舍五入为Solidity中最接近的整数。如果有问题,请改用乘数.
  3. 如果强行发送以太币怎么办? 由于可以将ETH强制发送到地址,因此请注意检查合同余额的所有不变编码,以及强制ETH行为如何影响代码.
  4. 是tx.origin 用过的? tx.origin绝不能用于授权,因为它包含您的地址,因此另一个合同可以调用您的合同并获得授权(如果使用了tx.origin,建议使用msg.sender()代替).
  5. 时间戳依赖性:如已知攻击部分所述,以太坊时间戳与同步的全球时钟断开连接,矿工可以利用以太坊的差异,因此应最大程度地减少对时间戳的依赖性.
  1.  提供后续步骤:对所发现的漏洞的建议性修复以及向前迈出的步骤。如果这些都是固定的,那么合同对于主网使用是否安全??

更多审核和错误示例

在这里,我们将从审计的历史示例和代码片段中找到见解,您可以将其应用于自己的智能合约审计。智能合约审计领域中的实体数量不断增加,其框架范围从以评论为重点到以测试为重点,各有千秋.

对于“未经检查的发送”错误的示例,“黑客,分布式”博客提供了以下代码段:

如果(gameHasEnded && !(prizePaidOut)){

winner.send(1000); //向获奖者发送奖品

awardPaidOut =正确;

}

如审核步骤部分所述,应始终仔细研究send()的使用。在这种情况下,send()方法可能会失败,从而使游戏赢家无法获得酬劳。对于类似拍卖这样的用例,可能存在类似的漏洞,在这种情况下,潜在的大笔资金面临风险.

按照 以太坊文档, 可能会发生此故障 “如果调用堆栈深度为1024(始终可以由调用者强制使用),并且如果接收者的电量用尽,它也会失败。” 该文档提供了解决方案 “总是检查汇款的返回值,或者甚至更好:在收款人提取资金时使用一种模式。”

根据文档建议,黑客,分布式支持该解决方案…

如果(gameHasEnded && !(prizePaidOut)){

帐户[获胜者] + = 1000

帐户[失败者] + = 10

awardPaidOut ==正确;

}

函数withdraw(amount){

如果(帐户[msg.sender] >=金额){

msg.sender.send(amount);

accounts [msg.sender]-=金额;

}

}

…从而重构代码,使发送失败一次仅影响一个参与者.

ConsenSys最佳实践框架提供了许多“好的和坏的代码”示例,其中涵盖了已知的攻击.

实用性^ 0.4.4; // 坏的

语用强度0.4.4; // 好的

例如,上面指出,编译指示应锁定到特定的编译器版本,以避免使用其他版本部署合同,这可能会增加未发现错误的风险.

uint256常量私有盐= block.timestamp; // 警告

另外,该块时间戳的代码应该是一个标志,以便您仔细检查以下时间戳的使用情况.

我们鼓励您分析以下推荐的许多其他示例 共识富人

审计工具作为补充

全面的审核可能包括测试以及文档和用例,这些由用户行为来解释。在这种情况下,应使用行为驱动开发(BDD)做法,该做法可与开发的智能合约测试方面相提并论,但应侧重于安全性而非功能.

为了使用松露来审核以太坊智能合约,请使用标准的npm install -g松露来安装框架,然后使用松露init来创建项目结构(假设您先前已获得 node.js).

导入合同和库以检查测试条件之后,此过程着重于编写测试并在测试网络中执行测试。您可以使用常规的assert()或测试框架,例如 hai. 最后,只需围绕我们已建立的步骤进行测试,例如检查上溢和下溢,测试功能限制,确保返回值的格式正确,等等。.

许多以智能合约为中心的去中心化应用程序已经实施了各种软件工具来辅助审计实践。这些工具(例如漏洞的自动代码检查)可以用作补充,但不能代替正式的审核过程。如前所述,一种选择是 秘银, 可用于检测uint上溢和下溢。另一个工具是Etherscrape, 这里 使用send()时刮取以太坊的实时合约以获取重入错误。也有去中心化的审计平台,例如 富翁 在工具不够用的情况下将公司和自由审核员聚集在一起. 

提供后续步骤

根据发现的漏洞的严重性,建议重点关注合同的某些方面以进行改进。您可能还会建议赏金漏洞和持续的渗透测试,作为在启动之前发现其他漏洞或问题的有效方法, 以太坊赏金 作为模特.

请注意,由于代码重构可能会引入新的漏洞,因此新添加的合同会将其置于未经审核的状态。最后,在公共或私人审计中创建问题咨询点.

结论

本指南提供的审核概述总体上适用于智能合约,但针对以太坊合约量身定制,以太坊合约是迄今为止最受欢迎的交易,因此交易资金最多,使它们面临最高的攻击风险和最大的审计需求.

现在,您拥有执行智能合约审核的工具,资源和专有技术–继续提高区块链空间的安全性和可信度。如果您有兴趣获得报酬以审核智能合约,或者如果您需要对智能合约进行审核,请签出 Bountyone.io

进一步阅读

由于区块链技术仍是一个新兴且迅速发展的领域,因此没有适用于所有解决方案的资源,因此我们建议您使用多种资源以增进您对本指南的理解.

01. “智能合约安全最佳实践” 经过 ConsenSys

02. “审核已部署的智能合约,而不是GitHub!” 经过 ConsenSys

03. “审核智能合约+最危险的实体攻击的终极指南”  由Merunas Grincalaitis

04. “开发智能合约:智能合约审计最佳实践” 经过 斯玛蒂姆

05. “智能合约的审计和安全编码的重要性” 在 ETH新闻

06. “以太坊智能合约安全” 经过 齐柏林飞艇解决方案

07. “ EtherCamp的Hacker Gold(HKG)公共代码审核” 经过 齐柏林飞艇解决方案

08. 固化:智能合约的全面审核服务

09. SmartDec:工具驱动的智能合约安全平台

10. 哈佛创新实验室审核 在 经验丰富

11. 对以太坊经典Multisig钱包进行的安全审核 经过 Dexaran

12. “扫描以太坊合约中的“未经检查的发送”错误” 经过 黑客,分布式

Mike Owergreen Administrator
Sorry! The Author has not filled his profile.
follow me