李雷孝,郑 岳,高昊昱,熊 啸,牛铁铭,杜金泽,高 静
1.内蒙古工业大学 数据科学与应用学院,呼和浩特010080
2.内蒙古自治区基于大数据的软件服务工程技术研究中心,呼和浩特010080
3.内蒙古工业大学 信息工程学院,呼和浩特010080
4.内蒙古农业大学 计算机与信息工程学院,呼和浩特010011
近几年来,新型数字货币发展迅速,其中以比特币(bitcoin)为代表的数字货币的价值和社会影响力已经不可估量[1]。2008 年Nakamoto[2]在比特币白皮书中首次提出区块链的概念,自此区块链逐渐进入人们的视野。2015 年区块链的发展迎来了大爆发,逐渐壮大起来。随后区块链被逐步应用在金融[3]、交通[4-7]、医疗[8-10]以及物联网[11-13]等诸多传统领域当中。随着区块链的发展壮大,智能合约越来越多地被人们关注和提及。智能合约的概念在1994年由Szabo[14]首次提出,但是由于时代发展的局限性,智能合约并没有很好的应用空间,直到区块链的出现,智能合约得到了发展和应用契机。智能合约逐渐成为区块链发展的关键环节,被视为区块链2.0的标志之一。
区块链作为一个让多个相互不信任的各方使用加密货币进行交易的平台,使用对等网络解决交易过程中的信任问题,使得对等双方能够就交易达成一致。与区块链的发展相结合,加密货币得到了快速的发展。加密货币通常采用严密逻辑设计的共识协议(如工作量证明(proof of work,POW[15])、权益证明(proof of stake,POS)等),由其底层网络中所有参与的节点同意,网络的计算节点负责在分布式账本——区块链中记录交易后的状态。在众多区块链网络中,由于以太坊[16]的实现方式能够使开发者使用区块链编写去中心化应用程序(Dapp)[17-21]和智能合约,在区块链社区中越来越受欢迎。以太坊区块链平台是一种基于共识机制的全球化执行的虚拟机,也称为以太坊虚拟机(Ethereum virtual machine,EVM)。它通过实现微内核来支持少量指令、堆栈、内存和存储,这支撑了分布式应用程序的全新概念。由于区块链复杂的协议在设计和编码的过程中难以避免出现人工的差错,随着区块链技术的发展和应用,其脆弱性和其他性能问题逐渐暴露在人们的视野中。许多重大安全事件的发生让人们对区块链的安全产生了越来越多的关注。尤其近年来发生的多起重大安全事件,例如2016 年TheDAO 事件[22],恶意攻击者利用可重入漏洞窃取了价值6 000万美金的Ether(以太坊加密货币),并由此造成了以太坊硬分叉;此外,2018年美链(beauty chain,BEC)[23]合约自身存在整数溢出的漏洞被攻击者利用,无限制地复制BEC 代币,导致BEC代币的价格跳水归零;与此同时还有诸如Rubixi利用不可篡改性骗取代币的庞氏骗局,King of the Ether Throne[24]采用拒绝服务攻击来骗取代币的攻击方式等一系列针对区块链平台的攻击。表1 给出了近年来区块链遭受的部分标志性的攻击事件。导致表1 中一系列安全问题出现的原因主要有智能合约一旦部署不可修改、合约执行后不可逆、编程语言自身问题或程序员的逻辑问题等。因此如何快速准确地进行漏洞检测是当前研究的重点,智能合约的漏洞检测已经成为当下的研究热点。
表1 区块链安全的重大事件表Table 1 List of major events in blockchain security
本文旨在介绍区块链中一些常见的漏洞情况,同时介绍一些漏洞检测的工具和方法,为之后的研究者提供一个综合化的有关漏洞工具和方法的介绍。另外本文涉及到的区块链相关代码如无特殊介绍均为以太坊虚拟机的Solidity语言。
区块链的诞生促进了智能合约的发展,通过智能合约编写去中心化应用也为区块链发展起到了促进作用。相比传统程序代码,智能合约肩负了保证参与多方公平性的问题,同时通过合约管理大量具有经济价值的加密货币。本章将简要概述区块链和智能合约所用到的技术和特性。
区块链是一个分布式的账本,其利用默克尔树、签名、对等网络以及哈希函数等技术,为区块链提供了安全可靠的技术支持。维基百科中对区块链的描述为:区块链是一种不断增长的纪录列表,这种记录称为“区块(Block)”,这些区块链接到一起,并使用密码加密以确保安全。区块链结合密码学,可以保证交易的可追溯性、不可篡改性、不可否认性和不可伪造性,支持数据安全共享和大规模协同计算,实现对用户身份和机密数据的隐私保护以及适用于需要高隐私性和安全性的分布式应用场景中[25]。区块链在金融、医疗和交通等社会领域当中的应用以及去中心化的特性等因素,使得区块链被认为是人类信用进化史上的第四个里程碑。
区块链系统是由多层架构共同构成的,区块链的系统架构可分为数据结构层、网络层、共识层、激励层、合约层和应用层六层,如图1 所示。区块链的底层是区块,区块间通过哈希指针链接形成区块链网络。区块包含区块头和区块体,由区块头中的哈希值来定位上一个区块的地址,而区块体包含实际的交易内容,区块体的内容由该块的所有者通过私钥进行签名以保证其安全性。网络层的结构是对等网络,对等网络是一种动态的网络拓扑结构,有很强的健壮性。共识层则是通过共识协议进行挖矿操作。区块链的参与者计算哈希值,首先计算出哈希值的块获得挖矿奖励。在此就延伸出了共识协议(工作量证明POW、权益证明POS 等)。合约层的主要内容为人工编写的智能合约。应用层则用于部署一些去中心化的应用、进行支付等操作,供人们更好地使用区块链为现实需求服务。
图1 区块链的系统架构图Fig.1 Blockchain system architecture diagram
尼克萨博在智能合约白皮书中提出智能合约的设计应遵循可观察性、客观可核查性、相对性以及可执行性同时减少执行的需要的四点设计原则和目标。同时其提出一个需要解决的问题,如何保证一个可信的第三方有足够的判断力来恰当地承担任务,即如何保证第三方的公平性、非恶意性。随着区块链的出现,研究者发现智能合约与区块链可以完美地结合,用以实现去中心化。智能合约是运行在区块链系统上的一段代码,代码逻辑定义了合约内容。智能合约应用以太坊独有的二进制编码格式——EVM 字节码进行编码并存储于区块链中。然而,智能合约通常由高级语言编写(例如Solidity)通过智能合约编写去中心化应用程序,然后编译成字节码上传到区块链上。
图2 以HelloWorld 为例展示智能合约的部署流程。首先调用transaction 函数在矿工打包的时候会生成智能合约地址。智能合约地址的生成是由创建者的账号和发送的交易数作为随机数输入,通过Kecca-256加密算法重新创建一个地址作为账号。即最后合约地址对应合约的代码会保存在区块链数据库中,调用者只需要有合约地址和abi文件就可以调用合约的代码。
图2 智能合约的部署流程Fig.2 Deployment process of smart contract
虽然智能合约促进了区块链技术的发展,但是由于智能合约编写语言自身缺陷或程序员编写过程中出现的逻辑错误等问题,使智能合约产生了一些漏洞,因此造成了智能合约成为攻击者攻击的目标。一些统计显示智能合约中的漏洞是普遍存在的,例如整数溢出漏洞、重入攻击、拒绝服务攻击等都是常见的智能合约漏洞类型。
智能合约作为区块链技术的重要组成,通过编写智能合约在区块链上部署去中心化的应用程序为区块链快速发展提供了帮助。但同时大量针对智能合约的漏洞也暴露在漏洞检测人员的视野中。在漏洞研究中,据统计存在25 种左右的常见漏洞。Atzei等人[26]对当时存在的智能合约漏洞,根据Solidity、EVM 和Blockchain 三个层级进行了分类。表2 展示了Nicola 对漏洞的分类。本章将列举八种以太坊中常见的漏洞,并对部分漏洞代码进行重现。由于智能合约典型漏洞案例大多由以太坊智能合约引发,并且研究者常以以太坊智能合约作为研究对象进行研究。因此本文以以太坊智能合约作为研究对象,详细描述了智能合约安全漏洞。
表2 以太坊漏洞分类Table 2 Ethereum vulnerabilities classification
重入攻击漏洞是区块链网络中被频繁利用的漏洞之一,TheDao 事件便是利用重入攻击漏洞进行的攻击。重入攻击漏洞常见于转账操作中,由于Solidity语言本身的原因,fallback[27]函数会在函数调用结束前让攻击者有机会再次执行被调用的函数。攻击者在执行转账操作时对fallback函数进行修改。在执行转账操作的时候,会涉及到跨合约的调用,此时攻击者会利用这些外部调用,设计恶意的代码多次调用漏洞合约中的转账操作,将账户中的余额不断消耗,直至gas耗尽。这里对重入攻击漏洞进行代码重现,具体代码如下所示。
重入漏洞代码示例:
在该合约中,withdraw()函数使用call.value()方法进行转账时,该方法会传递所有可用gas 进行调用。当该方法转账的地址为攻击者的合约地址时,就会调用攻击者合约地址的fallback函数。如果攻击者在自身合约的fallback 函数中写入调用withdraw函数的代码,就可不停地循环获取代币,不再执行balance[msg.sender]-=amount的减币操作,从而导致重入漏洞攻击的发生。
整数溢出的类型包括乘法溢出、加法溢出和减法溢出三种。由于EVM为所有的整数指定了固定大小的数据类型,一个整型的变量只能由一定范围的数字来进行表示。以uint8 为例,uint8 的范围为0 到255,因此如果存储一个256位的数值,则存储结果将会变为0。如图3所示,8位无符整数255在内存中占据8 bit位置,若再加1则整体会因为进位而导致整体翻转为0,进而导致原有的8 bit整数表示为整数0。
图3 整数溢出示例Fig.3 Integer overflow example
针对整数溢出漏洞,以太坊为开发者提供了SafeMath库[28],库中的数值计算操作会检测整数溢出行为,并在溢出发生时抛出异常。
以太坊合约开发者(Owner)具有合约的超级权限,包括冻结代币、增发代币、销毁代币、铸造新的代币以及终止合约运行等。若合约权限被攻击者窃取将造成严重影响[29]。访问控制漏洞的产生是由于智能合约的编写者没能准确检查合约中函数的访问权限,例如将一些应该设置为private 的函数不加区别或未定义权限,默认为了public类型。这些函数本应该是普通用户无法访问的,因此就导致攻击者有足够的权限去访问本不该被其访问的函数或者变量。
访问控制漏洞示例:
如上所示,setOwner 函数未定义函数类型,因此其类型为public,此函数可以用于设置合约的拥有者。但其标注为public 类型就使得所有人都拥有了访问的权限,因此攻击者可以轻松地设置其他用户为owner并窃取其中的加密货币。
与大多数区块链一样,以太坊节点通过汇总交易并将其形成块。一旦矿工解决了共识机制(例如以太坊的POW),那么该交易就被认为是有效的。解决该区块的矿工能够选择来自该矿池的哪些交易将包含在该区块中,这通常是由gas交易决定的。在这里有一个潜在的攻击媒介,攻击者可以观察事务池中是否存在可能包含问题解决方案的交易,修改或撤销攻击者的权限或更改合约中对攻击者不利的状态。然后,攻击者可以从这个事务中获取数据,并创建一个更高级别的事务gas,在交易公布之前将其交易打包存放在一个区块中。
如下代码示例所示,此合约包含10个以太币,如果矿工能成功查找到hash,则发放10 个以太币给第一个查找到此hash 的矿工。但是在这个过程中,攻击者可以时刻关注到交易池中所有人提交的答案,攻击者也可以随时检查答案的有效性,然后发起更高gas 的交易,从而获得这笔交易的10 以太币奖励。而第一个查找到此hash的矿工将一无所获。因此错误的交易顺序可能会对合约造成负面的影响[30]。
交易顺序依赖攻击代码示例:
对可预测变量的依赖[31]是由于在区块链中取随机操作存在伪随机行为,即攻击者可以通过某些手段去预测下一步的变量值,达到控制合约并造成不可预料的结果从而取得加密货币的目的。
在以太坊中,区块头包含一些以太坊自身特殊的字段来表示区块的属性值,智能合约可以通过以太坊提供的这些接口来读取相应的属性值,如block.coinbase(address)、block.gaslimit(uint)等。在以太坊中存在熵的概念[32],即随机性。由于以太坊不存在传统编程语言中的Random()函数,而是利用这些属性值产生随机数。聪明的攻击者会利用这些属性值去寻找随机数的生成方法,并窃取加密货币。同时由于一个区块的时间戳是由矿工决定的,并且允许有900 s 的偏移,这就给一些投机的矿工利用这个时间节点去抢先获取出块奖励的机会。
对可预测变量的依赖代码漏洞示例:
如上面展示了一个时间戳依赖的例子,矿工可以根据需要调整时间戳,因此如果合约中有足够的以太币,计算出某个区块的矿工将被激励选择一个now%15==0 的时间戳,这样便可有机会赢得这个合约。由于每个区块只允许一个人下注,也易受前置交易的攻击。由于块时间戳是单调递增的,矿工不能自主选择任意的块时间戳,这些块可能会被网络拒绝。
以太坊智能合约有一个全局变量tx.origin[33],它能够回溯整个调用栈并返回最初发起调用的合约地址。若合约使用这个变量做用户验证或授权操作,攻击者便可以利用tx.origin 的特性创建相应的攻击合约盗取以太币。例如,攻击者在自己的Fallback 函数中调用受害者合约的取钱函数,通过诱导受害者合约转账以太币给攻击者合约,而由于“tx.origin==owner”的缘故,会导致无法检测出异常,从而使受害者合约中的以太币全部转到攻击者合约账户中。
tx-origin漏洞代码示例:
如上所示,合同拥有者成功发送了一个交易给攻击者合约,这将触发Fallback函数执行。在Fallback函数中调用被攻击合约里的withdrawAll()函数。这将导致被攻击合约里的所有代币被提取到攻击者的地址。这是因为最初合约的调用者是受害者合约地址(这里是受攻击的合约地址)。因而,tx.origin等于所有者,在被钓鱼合约的第11 行上的require 语句就会不起作用,因此withdrawAll()函数得以继续执行。
拒绝服务攻击(denial of service,DOS)[34]就是用户想要进行的操作或服务请求无法被系统处理。DOS 的攻击方式有多种,其中针对智能合约的DOS攻击属于利用协议漏洞进行攻击的手段,攻击将导致合约在短时间内无法运行,或者某些情况下永久无法运行。因此在区块链网络上造成永久的“冻土”,即合约被锁定,用户的加密货币也随合约一同“冰封”。拒绝服务攻击的典型案例为Throne of King of Ether,在此游戏合约中,攻击造成了没有成功拿到王位的人不能取回作为保证金的加密货币,以下面的游戏合约为例展示拒绝服务攻击。在此游戏中,只有支付大于emperor的金额才能成为新的emperor,但要先退回之前的emperor 的加密货币才能更改新的emperor。如果前一个emperor 一直不接受退回的加密货币,则前一个emperor 就能一直保持emperor的身份,以此造成拒绝服务攻击。
拒绝服务攻击代码示例:
动态数组双重访问攻击(dynamic array doubleaccess attack)区别于双花攻击,由Chang 等人[35]于2020 年提出。如图4 所示,由于智能合约或者EVM底层的机制,不同的变量可能存储在同一位置。但是某些情况下会导致存储的变量被覆盖,进而导致合约的执行不正确。动态数组双重访问攻击会导致两种主要的危害。
图4 动态数组和映射变量双重访问攻击示意图Fig.4 Schematic diagram of double access attacks on dynamic arrays and mapping variables
(1)绕过限制条件。即可以修改if或require的条件分支语句修改状态变量的值。
(2)特权升级。攻击者利用此漏洞破坏合约的存储结构,可以任意执行变量覆盖的操作,从而执行一些普通用户无法执行的操作。
因此可以设计在同一存储位置中访问不同类型的变量,进行双重访问攻击,通过控制合约执行过程,窃取以太币。
目前在以太坊环境中缺少有效的工具能够对动态数组双重访问攻击进行有效的检测,依赖人工方法进行检测效率低,因此设计有效的动态数组双重访问攻击漏洞检测工具是当前的重要研究方向。
第2章介绍了八种常见的漏洞类型,由于区块链不可篡改性,需要在上链前把智能合约中存在的漏洞进行检查,避免存在漏洞的智能合约被部署上链。本章介绍了形式化验证、符号执行、模糊测试以及机器学习等几类智能合约漏洞检测的方法,并分别介绍了对应方法所使用的一些工具。
目前,形式化验证技术已经在核电、航天等高安全要求的领域取得了成功应用,通过将形式化方法应用于智能合约漏洞检测,可以使得智能合约的生成和执行有规范性约束,从而保证合约的可信性和可靠性。形式化验证是智能合约安全分析的重要技术之一。通过形式化语言把合约中的概念、判断、推理转化成形式化模型,从而消除合约中的歧义性和不通用性,然后配合严谨的逻辑和证明,验证智能合约中函数功能的正确性和安全性[36]。这些形式化验证方法主要包括以下四类方法:基于类BAN 逻辑的形式化方法[37],基于模型检验的形式化方法[38],基于密码学原语代数属性的形式化方法和基于定理证明的形式化方法。
常见的形式化验证方法包括模型检测和演绎验证。模型检测列举出所有可能的状态并逐一检验,这种方法的基本思想通过数理逻辑证明的方式,验证代码在规范描述的前提下满足某些特性。
ZEUS[39]是一款利用形式化验证方法进行漏洞检测的工具,该工具支持将Solidity 语言编写的智能合约转换为LLVM(low level virtual machine)的中间语言表示,再利用形式化验证方法验证安全性。但其无法检测跨函数的重入攻击和一些跨功能的分析策略[40]。
Isabelle/HOL 是Hirai[41-42]提出的针对EVM 字节码进行检测的形式化验证工具,将EVM 字节码通过lem language 转换成一个形式化的模型,然后通过形式化的模型去验证代码逻辑中是否存在问题。基于Isabelle 方法,研究人员将其进行了改进,放弃了lem language 这种相对来说低效率的方式,而是采用Fframework(一种航天领域使用的形式化漏洞验证框架)[43]和K-framework(一种语义的整合框架)[44]来进行验证。
此外国内的一些学者也提出了自己的形式化验证模型,董春燕等人[45]提出了一种基于CPN(colored Petri net)模型的形式化验证方法,用于Auction 合约的验证。该模型能成功检测出潜在可能发生不回退加密货币的漏洞出现的位置。欧阳恒一等人[36]借鉴数学归纳法的思想,优化SmartVerif(一种基于定理证明的形式化验证结合机器学习的形式化方法)模型验证过程,避免状态空间的无限遍历并能成功找出目标漏洞。
符号执行审计方法的主要思想是将代码中的变量符号化。通过符号化程序输入,符号执行能够为所有的执行路径维护一组约束,执行之后,约束求解器将用于求解约束并确定该执行的输入,最后利用约束求解器得到新的测试输入,检测符号值是否可以产生漏洞。符号执行法应用于智能合约漏洞检测的执行过程为:首先,将合约中的变量值符号化;然后逐条解释执行程序中的指令,在解释执行过程中更新执行状态、搜集路径约束,以完成程序中所有可执行路径的探索并发现相应的安全问题。
赵伟等人[29]对智能合约反编译生成的字节码构建智能合约执行的控制流图,随后利用约束求解生成软件测试用例,对已知的五种类型漏洞达到了85%的检测成功率。图5为其符号执行过程流程图。
图5 符号执行流图Fig.5 Symbolic execution flow graph
Oyente[46]是第一个用于以太坊上的漏洞检测工具,该工具采用符号执行方法,直接检测EVM 字节码,支持重入漏洞、交易顺序依赖以及伪随机等安全漏洞的检测,但是该工具对于自杀合约和tx-origin的滥用问题并不能做到有效的检测。Mythril[47]作为一个符号执行的漏洞检测工具,通过对EVM 字节码进行分析,能够支持多达14种漏洞的检测。MythX[48]整合了Truffle和Remix等工具,能够支持多平台的漏洞检测。
面对现有符号执行方法检测速度较慢的问题,李宗鸿等人提出一种自底向上求解约束的改进符号执行方法[49]。结合深度优先遍历和广度优先遍历进行路径的选择,以此提高符号执行的代码覆盖率。该方法显著地提高了中等规模智能合约中的检测效率,并在正确率方面取得了不错的效果。
模糊测试是一种通过向目标系统提供非预期的输入并监视异常结果来发现软件漏洞的方法。模糊测试方法的核心思想是将自动或半自动化生成的随机数据输入到一个程序中,并检测程序的异常,以发现可能的程序错误。在模糊测试中用随机的坏的数据,即fuzz去攻击程序并观察出现问题的点。其好处在于这个数据是不符合逻辑的,因为程序存在的漏洞大部分若按照人的正常逻辑是无法观察到的,因此模糊测试是一项十分有效的漏洞检测技术。
ContractFuzzer[50]是一个利用模糊测试进行智能合约漏洞检测的黑盒测试工具。它使用智能合约的二进制接口生成交易,通过EVM执行这些交易,通过分析执行日志来检测安全漏洞。图6 展示的是ContractFuzzer 的检测流程。其通过第0 和1 步在以太坊官网获取开源的智能合约并通过对ABI 签名分析生成一个ABI规范的模糊测试输入,并在3、4、5步执行模糊测试过程。
图6 ContractFuzzer架构图Fig.6 Overview of ContractFuzzer
SoliAudit 是一款Liao 等人[51]提出的机器学习和模糊测试相结合的漏洞检测工具,SoliAudit 动态模糊器不仅能够模糊函数参数,还可以模糊区块链环境的一些参数,如gas和ether。同时利用操作码特征进行机器学习分类,漏洞识别达到90%,还可以自动生成模糊测试合同以及适应新的漏洞。
GasFuzzer[52]是一个利用模糊测试方法,用于检测交易中有较高gas消耗异常的工具。通过提出gasgreedy 和gas-leveling 两种策略有效提高了漏洞检测的效率。相比ContractFuzzer 漏洞检测工具,效率提升了约28%。
机器学习作为当前计算机研究方向的热点,由于在漏洞检测中可以提供较高的自动化程度和漏洞检测效率,与漏洞检测结合也成为了大量学者的研究热点。
传统的智能合约代码审计工具高度依赖专家定义的固定规则或模式来检测智能合约的漏洞,但专家规则容易出错,一些复杂的模式也不容易被覆盖。同时基于规则开发的检测工具可伸缩性有限[30],随着智能合约数量的爆炸式增长,这种模式的适用性越来越低。机器学习在漏洞检测中可以提供较高的自动化程度和漏洞检测效率。因此利用机器学习的方法逐渐进入人们的视野。本节会介绍几种利用机器学习进行智能合约漏洞检测的工具和方法。
Xiong等人[53]提出了一种利用强化学习的智能合约漏洞检测方法SmartVerif,该方法增强了漏洞检测的自动化程度,提高了检测的准确率。但是由于该方法需要为每一种协议训练一个独立的模型,或是利用预训练和优化的网络来验证协议,存在验证时间增加以及精度降低的问题。因此如何训练通用的模型,增加检测效率将是以后的研究重点。通过实验与传统的漏洞检测方法对比,证明该方法比传统的漏洞检测方法在效率和准确率方面均有大幅度的提高,同时其自动化程度也比传统方法更加强大。
Xing 等人[54]提出用Tensorflow 构造卷积神经网络模型以漏洞合约的切片矩阵做输入,用卷积神经网络算法分别对has_short_address、has_flows和is_greedy三个漏洞合约代码片段训练,得到三个检测合约漏洞的分类模型。利用Tensorflow 构造卷积神经网络模型,只使用卷积层,然后导出的矩阵被提供给神经网络,最后得到基于卷积神经网络的分类模型。利用卷积神经网络和随机森林做对比实验,但对比实验结果显示随机森林方法的效果更好。
Momeni 等人[55]引入机器学习预测模型,采用两个静态代码分析器标记了1 000 个以太坊平台使用的智能合约。其对漏洞的检测平均准确率达到95%。
在使用机器学习的方法中,多将代码转换为控制流图(control flow graph,CFG),利用CFG 进行切片,对切片矩阵建立机器学习的预测模型,利用CFG建模的同时配合字符串匹配和模糊测试等代码审计技术对漏洞进行检测,以获得较高的准确率和效率。
Qian[56-57]团队致力于将专家定义的安全模式与机器学习相结合。将源代码的控制和数据流语义转换为合约图,同时设计一个消除阶段来进行图的归一化。提出了一种新的消息传播网络(temporal message propagation network,TMP)用于从规范化图中提取图特征,并将图特征与设计的专家模式相结合,产生最终的检测系统。利用深度学习网络(deep neural networks,DNN)、无度图卷积神经网络(degree-free graph convolutional neural network,DR-GCN)、双向长短期记忆(bi-directional long short-term memory,Bi-LSTM)以及长短期记忆(long short-term memory,LSTM)进行针对某一类型漏洞的精确检测。此外还提出了智能合约的合约片段表示,用于捕捉基本的语义信息和控制流依赖。在检测性能的表现方面,利用深度学习网络的方法在针对重入攻击、时间戳依赖以及无限循环的检测准确率分别达到了89.15%、89.02%和83.21%。其他学习模型也对重入攻击有较好的检测准确性。
Tann等人[58]也使用机器学习长短期记忆(LSTM)对智能合约的漏洞进行顺序学习。该方法能够快速检测到智能合约的漏洞,并实现了99%的准确率,保证了智能合约上链之前的安全性。
除了现有的符号执行和形式化验证等主流检测方法外,还有许多利用其他方法和思想的漏洞检测方式。
在以太坊中,透明公开的智能合约占了总交易量和总交易金额的2/3 左右,但是有大约77.3%的智能合约是不透明非开源的。针对这种因非开源导致无法利用正面解析智能合约源代码的问题,Zhou 等人[59]提出了Erays 方法,一种利用逆向工程的思想来进行漏洞检测的方法。Erays方法用于研究以太坊系统中不透明的智能合约,从十六进制编码的智能合约作为输入,将十六进制的字符串分解为EVM指令,从十六进制字符串的第一个字节开始,每个字节被顺序解码成相应的指令,而后从基本块中恢复控制流图,以此来进行漏洞检测工作。但是该方法也存在巨大的弊端,由于没有源代码,该项工作的代价昂贵,因此该工具也难以实现高自动化,更适合于手动分析并且高度依赖专家经验。
除逆向工程外也有在传统漏洞检测方法的思想上做出改进的技术方法,韩松明等人[60]提出了Dc-Hunter。Dc-Hunter 检测方案,通过计算待检测合约与已知漏洞合约之间的相似性检测智能合约,同时此方法还可以用于发现潜在的蜜罐合约。该方法无需源码和预先定义的漏洞特征,通过应用切片降低无关代码影响,并使用图嵌入算法来捕捉函数的结构信息。
在利用传统特征代码匹配的方法中,Slither[61]应用广泛使用的污点跟踪技术和数据流来提取细化信息。它将智能合约转化为中间表示SlithIR,利用这种中间表示与问题代码做匹配进行检测。其性能在准确率和时间效率方面取得了不错的表现。同时EASYFLOW[62]也是利用污点跟踪来进行漏洞检测的工具,在对具体的漏洞合约检测时同样取得了不错的效果。同样的,SmartCheck[63]也是一种利用中间表示来进行漏洞检测的方法,通过将智能合约源代码转换为一种基于XML 的中间表示,从而形成对漏洞的有效检测,但与ZEUS一样,若语义定义不准确,会大大降低其准确率。传统的静态分析方法很容易应用到其他区块链平台和不同语言编写的智能合约中,但是其执行效率和准确率问题有待提高。
本节通过使用检测速度、适用范围、自动化程度以及准确率四项评价指标来说明上述各类检测方法存在的问题及其局限性。
形式化验证方法审计智能合约安全的工作,从应用之初就存在大量的问题。形式化验证方法的局限性在于其应用了大量的数学推导和证明过程,因此使得一些非专业人员很难参与此类方法的研究,导致基于该种方法的检测工具发展缓慢。同时由于复杂的推理和验证过程,造成其适用范围降低且自动化程度较低。
符号执行方法需要对源码转换成操作码(OPCODE)之后生成控制流图,而后需要转换为一种自定义的语义再进行验证。这一个复杂的过程中涉及到大量的路径遍历和遍历路径的约束问题,路径问题就很难避免出现路径爆炸,因此是十分耗时的。若通过限制条件减少遍历路径,则会使得检测准确率降低。
模糊测试方法与其他方法相比,可用工具最少,各类评价指标上的表现都不尽人意。主要原因在于模糊测试需要精巧的设计测试过程,前文提到的模糊测试方法需要随机种子进行检测,但随机种子很难覆盖全部路径,因此导致其检测的准确率不能达到理想的状态。
机器学习方法在检测结果方面的效果表现最为出色,但是取得出色的结果依赖于大量开源智能合约的支持。但开源智能合约在整个已部署的智能合约中占比较低,会影响这类方法的性能。随着开源智能合约的数量提升,机器学习方法的效率也会提升。同时可以注意到,机器学习方法在适用范围方面表现较差。由于机器学习方法的学习过程要具体到某一个具体的函数或某一类漏洞的代码段,需要对每种漏洞进行建模,这就降低了其通用性。
特征匹配方法作为一种静态分析方法,其检测速度快并能够迅速响应新漏洞的优势明显。不同于传统的漏洞检测,区块链的漏洞检测受限于开源智能合约的数量。但是以太坊中有超过一半的非开源智能合约,在无法获得开源代码的情况下,漏洞检测人员可以获得其操作码但是对操作码的分析代价十分巨大。因此该方法的适用范围有限,同时由于智能合约函数和一些特征自身限制,导致特征匹配方法的漏报率较高。
本文通过实验分析对比了各种漏洞检测方法,通过实验数据更直观地体现各种方法的优缺点。从以太坊官网中选取450个智能合约样本,通过实验对VaaS、Oyente、ContractFuzzer、DR-GCN、Slither 五种具有代表性的工具进行测试,并针对可重入和可预测变量的依赖两种类型漏洞进行检测。从准确率、支持漏洞数量和平均检测速度三方面对漏洞检测工具的性能进行评估。本文实验具体实验环境为操作系统Windows 10,CPU Intel®CoreTMi5-10500 CPU@3.10 GHz 3.10 GHz,内存16 GB,Python版本为2.7.2和3.7.0,GPU 为NVIDIA GeForce RTX 2060 super。实验结果如表3所示。
表3 各类漏洞检测方法的评价表Table 3 Evaluation of various vulnerabilities detection methods
从表3中的实验结果可以看出,在准确率方面机器学习方法DR-GCN 表现出较高的精度,同时在检测速度上具有绝对的优势。VaaS作为一个成熟的商业工具在支持的漏洞数量上表现出较强优势。但同时也可以看出形式化验证方法和模糊测试方法在检测速度上的劣势相当明显。机器学习方法虽然在准确率和检测速度方面拥有较强的优势,但其难以建立起通用的模型,因此支持的漏洞数量较少。
需要说明的是,由于形式化验证方法的复杂性以及缺少足够的开源工具,因此选择VaaS作为本次实验对象。VaaS是一款成熟的商用漏洞检测工具,因此其支持检测的漏洞数量和准确率都有不俗的表现。
(1)符号执行的路径优化
符号执行方法由于路径选择的需要将面临路径爆炸问题,如何缩短符号匹配的路径、优化最优路径、避免路径爆炸问题是以后提高符号执行工具效率的重点方向。
在优化符号执行中,通过广度优先遍历和深度优先遍历结合,提高符号执行代码覆盖率。在对路径进行遍历的同时,对路径的选择进行优化,精简对程序无影响的路径,以此缩短漏洞检测的时间,提高执行效率。
(2)自动化程度较低
当前多数工具的自动化程度较低且高度依赖人工检测和专家方法,部分检测工具的自动化程度不高,随着智能合约数量的增长,自动化程度低的弊端逐渐显现,在工作量提高时检测效率低的问题亟需解决。因此如何提高自动化程度将是未来研究的重点。
利用机器学习的方法可以使自动化程度显著提高,在未来的研究中,应致力于深度学习方法的研究,由此提高智能合约漏洞检测的自动化程度和整体效率。
(3)漏洞类型覆盖率低
现阶段智能合约的漏洞类型多,不同区块链网络编写智能合约采用的语言也不尽相同,这也给漏洞检测带来了困难。本文调研的众多漏洞检测工具个体支持检测的漏洞类型最多不超过10 种,但现有常见的漏洞类型多达20多种。因此下一步的重点是整合更多的漏洞检测工具以提高漏洞覆盖率,同时可以致力于使用机器学习方法建立通用的模型,使用机器学习方法能更好地提高漏洞覆盖率,以此作为今后的研究重点。
(4)漏洞检测效率较低
当前的漏洞检测准确率较低且速度较慢,如何提高漏洞检测效率,即如何解决在检测过程中出现的假阳性、真阴性问题以及如何提高漏洞检测的速度是未来研究过程中需要探索的问题。当前漏洞检测效率低的原因是形式化验证等方法需要大量的数学推导同时依赖专家经验,此计算过程时间较长,因此优化数学方法、优化搜索路径或使用深度学习方法都能有效提高检测效率。
(5)智能合约开源程度低
当前智能合约的开源程度较低,这就给漏洞检测造成了困难。由于现阶段非开源智能合约超过半数,促进智能合约的开源才能有效与机器学习结合,以此为研究者提供更好的代码检测环境。同时利用这些非开源的智能合约进行逆向工程的漏洞检测,提高对非开源智能合约的利用,将是解决现有开源智能合约不足问题的方法。
(6)机器学习方法构建通用模型
当前机器学习方法虽然能够实现较高的学习效率与较好的学习结果,但是当前智能合约数量的增长速度快,漏洞类型也越来越多,而机器学习方法大多只针对某一具体漏洞或具体函数进行学习,对新漏洞的适应能力不足,因此需要形成通用的漏洞检测模型。
构建通用模型或适用性更广的模型来同时检测更多的漏洞将是使用机器学习方法未来研究的方向。通过构建通用检测模型,将会使机器学习方法更快速、方便地服务于漏洞检测,并做到对新型漏洞的快速响应。
(7)可移植性低
当前的智能合约编写语言种类繁多,平台较多,多数漏洞检测软件的跨平台性差甚至完全不支持跨平台。未来如何使成熟的漏洞检测工具在支持更多智能合约语言的同时提高其跨平台性,以及使漏洞检测工具更好地发挥其检测的效率将是研究的重点方向。整合不同漏洞检测工具,发挥其不同的性能优势,将会更好地提高检测工具的检测效率和可移植性。
(8)缺乏统一的评价指标和完善的漏洞合约库
现阶段智能合约的漏洞检测工具评价标准集中在速度、准确率等指标,缺少统一的评价指标。而且每种工具支持的漏洞数量、跨平台性等不尽相同。因此需要整合漏洞检测工具的评价标准,综合考虑可移植性、自动化程度以及准确率等指标形成统一的评价标准。同时,关于智能合约的测试没有标准的测试集,因此造成各工具对比数据可信度大大降低。下一步研究应建立完善的存在漏洞的智能合约库,为未来漏洞检测的研究和攻击行为的预防提供支持。
本节总结了不同智能合约检测方法的问题并对部分问题给出了改进思路。未来,总结各种方法的利弊,综合各种方法的长处,开发更加高效的漏洞检测工具将是未来研究的重点,以此形成更加安全的、可靠的智能合约环境。由于传统漏洞检测方法存在以上描述的各种问题,倡导在未来的研究中加大机器学习的研究力度。与此同时,由于机器学习方法对数据高度依赖,在未来建立统一的检测标准和相关数据集,有助于开发者更好地开发漏洞检测工具。
区块链是计算机技术发展的重要产物。密码学、智能合约、对等网络等的综合应用,使区块链正在改变交通、医疗、金融等传统行业。在快速的发展过程中,安全问题也大量涌现。TheDAO、Beauty Chain等事件的出现为安全人员敲响了警钟,在利用区块链去改变社会的同时,也应该对其安全性进行审视,解决安全漏洞问题。本文简要介绍了重入漏洞、整数溢出漏洞、访问控制漏洞等八种常见的漏洞类型,并对部分漏洞代码进行了重现,让研究者更直观地了解漏洞。通过对形式化验证、符号执行、机器学习等五类漏洞检测方法的介绍,引入对应类型漏洞检测方法的工具,对这些方法和工具进行了讨论分析,并给出未来智能合约漏洞检测研究的一些展望。