扫描实时以太坊合约以查看未检查的发送错误。 第二部分

继续“扫描实时以太坊合约的未检查发送错误”一文。 第1部分“


大约一年前(以太坊处于“前沿”发行时),受欢迎的EtherPot彩票合同[9]也遭受了同样的错误。 BTCRelay的早期版本也显示了此错误[7] 。 尽管在先前的安全审核中检测到危险,但首先应用了不正确的更正[8]


实时区块链上未经检查的发送错误检测


这些错误有多普遍? 他们听警告吗? 是否采用了最佳做法? 我们通过分析以太坊区块链的数据以及在etherscrape.com上找到的Solidity代码存储库,以经验方式回答这些问题。 为此,我们正在开发一个简单的程序分析工具,该工具可以检查区块链合同并使用试探法检查是否使用了最有效的保护方法之一。 清单2显示了以太坊文档中推荐的第一种安全技术,该技术应检查send的返回值并引发异常。 为了检测这种方法的使用,我们使用一个大概的近似值:我们只是看send的返回值是否被忽略。

清单4说明了UMD手册中推荐的第二种安全技术,该技术通过发送测试消息直接检查调用堆栈是否已满 。 为了发现这种技术,我们再次使用一个粗略的近似值:除了send命令外,我们只是检查是否正在发送一条消息。

如果没有这些启发式指标,我们得出结论,没有遵循最佳实践建议之一。 我们使用与已编译的EVM字节码的简单模式匹配来实现这些试探法。 有关如何执行此操作的更多详细信息,请参见附录[12]


有多少合同易受攻击?


让我们首先检查Solidity源代码的Etherscrape存储库中的启发式方法。 截至2016年3月20日,Etherscrape中继包含361个Solidity合同程序,其中56个包含send语句。 在这些合同程序中,我们假设大多数(至少56个中的36个)不使用任何防御性编程方法。

即使合同不使用任何保护性技术,它可能也可能没有真正的漏洞。 我们手动检查了Solidity合同以确认该漏洞。 就我们的目的而言,即使send命令无法运行,如果合同的状态可以更改,我们也认为合同是易受攻击的(因此,我们将查看清单5中的易受攻击的代码)。 我们确认存在绝大多数漏洞,其中36份合同中有32份。


同样,我们的启发式方法不能保证防御性编程的正确应用。 以WeiFund为例,它是一种分散式开源众筹DApp。 该合同具有两个功能: 退款()支出() ,这会欺骗我们的启发式方法。 以下是退款摘录。


function refund(uint _campaignID, uint contributionID) public { ... receiver.send(donation.amountContributed); donation.refunded = true; ... if(c.config != address(0)) WeiFundConfig(c.config).refund(_campaignID, donation.contributor, donation.amountContributed); } 

在此代码中,仅在某些情况下,消息会发送到WeiFundConfig(c.config)以调用退款方法。 如果c.config为空值,则该合同确实容易受到调用堆栈攻击。 选中*时,没有通过我们的启发式测试的Solidity程序实际上没有直接应用推荐的最佳调用堆栈测试实践。 *

然后我们将注意力转向以太坊区块链上的起草合同。 我们查看了日期为2016年3月20日的图像(时间戳:1184243)。 该快照包含总共13645个区块链,这些区块链显然是由Solidity编译器生成的,其中只有1618个(11.8%)包含send命令。

其中,绝大多数似乎没有使用任何防御性编程技术。


TheDAO中的递归竞赛问题呢? 当今最激动人心的智能合约TheDAO [11]遭受了一个完全独立的错误,那就是它不是“可以安全使用的” [13] 。 这是另一种(连接的但截然不同的)不安全编程,在以前的安全检查中也曾期望过这种安全编程[6] ,但是,像以前一样,今天许多合同很不安全。 未来的工作是制造一种也可以检测到此类错误的工具。


哪里出错了?


我们不希望至少在目前为止,基于智能合约的编程不会完全简单。 然而,令人惊讶的是,尽管以太坊生态系统的发展在很早以前就已经描述了这种错误形式,但这种错误形式如此广泛。

2015年的一份报告[6]向以太坊开发人员提出了此建议:

当前,文档中提供的编程示例不足以传播用于编写安全合同和解决天然气机制问题的最佳实践。 C ++入门教程经常跳过
错误检查的可读性,从而导致许多安全错误。 以太坊例子应该教出最佳习惯。 建议:提供更多仔细设计安全合同的示例。”

我们仅知道此问题的一个正式答案,即在前面提到的官方Solidity文档中添加警告[3],以下重复说明:“使用send时有一定危险:如果调用堆栈深度为1024(始终可以由调用方调用),并且如果接收方的电量用尽了也会失败,因此为确保安全广播,请始终检查send的返回值或什至更好:使用模式 收款人在其中提款。”


我们认为,这种观察不足以记录问题。 它仅提供了不完全的缓解措施,仅描述了一种危险形式,可能使读者误解其程度。


  • 更新:
    Peter Wesenes还详细说明了Solidity文档的不足。 [16]


此外,警告似乎经常被忽略。 因此,我们认为有必要采取其他预防措施。



Etherscrape如何提供帮助?


我们相信使用静态分析工具,即使是本文中介绍的粗略分析工具,也可以帮助提高智能合约的质量。在Etherscrape,我们将此类分析工具集成到了公共Web服务中,并在该工具的页面上添加了链接她什么时候准备好。 通过突出显示可能发生错误的位置,这将使查看智能合约代码变得更加容易。 我们假设这种智能合约的用户(例如,TheDAO或其报价的潜在投资者)可以在存钱之前轻松使用诸如健全性检查之类的工具。 甚至非技术投资者也可以要求开发人员负责解释他们如何对代码中指出的问题做出反应。

Etherscrape还可以通过分析公共区块链并控制此错误的发生率来提供帮助,例如,这可以帮助确定应分配多少资金来研究和开发静态分析工具。 另外,诸如solc之类的编译器可以集成此类分析,从而在可能出现错误时向程序员提供警告。


推荐读物



Source: https://habr.com/ru/post/zh-CN430684/


All Articles