智能合约攻击之Oraclize服务
摘要: 近日,在众多攻击案例中,有些漏洞成因或攻击模式少有研究涉及,也出现了一些比较隐蔽的攻击链。一起分析一下因为使用Oraclize服务的疏忽引起的漏洞和如何在自己的合约中使用Oraclize服务。
近日,在众多攻击案例中,有些漏洞成因或攻击模式少有研究涉及,也出现了一些比较隐蔽的攻击链。下面WF曲速未来跟你一起分析一下因为使用Oraclize服务的疏忽引起的漏洞和如何在自己的合约中使用Oraclize服务。
使用Oraclize服务的疏忽
为了将区块链技术应用到线下,例如将飞机延误险、数字货币兑换等业务上链,区块链需要具有访问链外数据的能力。但是如果智能合约直接从外部服务获取数据,由于网络延迟,节点处理速度等各种原因,会导致每个结点获取的数据不同,使区块链的共识机制失效。
现有的解决方案是使用第三方发送区块链的交易,交易会同步到每个节点,从而保证数据的一致性。Oraclize是一个预言机,为以太坊等区块链提供数据服务,它独立于区块链系统之外,是一个中心化的第三方。Oraclize可以提供的数据访问服务包括随机数、URL访问、IPFS等。Oraclize的架构如图所示:
Oraclize不是链上直接可以调用的函数,而是一个链外的实体。为了抓取外部数据,以太坊智能合约需要发送一个查询请求给Oraclize,当Oraclize监听到链上有相关请求时,立即对互联网上的资源发起访问,然后调用合约中的回调函数__callback将查询结果返回区块链。
例如,用美元兑换以太币的智能合约的数据查询语句如下:
监听到请求后,Oraclize会访问URL获得查询结果,然后调用__callback的函数,Oraclize返回的数据通过__callback函数参数传回智能合约。上图中函数调用的参数[3]中的“3334312e3533”即为当时的汇率:1ETH = $341.53,随后智能合约会根据这个查询结果进行后续的逻辑处理。
SIGMA合约使用了Oraclize服务查询汇率。该合约的__callback回调函数如下:
由于__callback函数中存在整数溢出,导致owner的代币余额被下溢成一个很大的值,导致代币增发。从代币份额排名可以看出攻击者的账户地址为0x2ef045a75b967054791c23ab93fbc52cc0a35c80,而该地址并不是创建合约的账户地址(0xC7e92D8997359863a8F15FE87C0812D7A3a8F770)。
跟踪Transactions,发现0xC7e92D8997359863a8F15FE87C0812D7A3a8F770调transfer_ownership将合约的owner设置为0x2ef045a75b967054791c23ab93fbc52cc0a35c80。
针对这个漏洞是否使用SafeMath就可以解决了呢?答案是否定的。在Oraclize调用__callback之前,有用户对查询函数的调用,而且这个调用花费以太币。
使用SafeMath的情况下,发生溢出的事务会回滚,但本例中能够回滚的只有Oraclize对__callback函数调用的事务,而之前用户花费以太币发生的事务则无法回滚。WF曲速未来表示这个现象的根本原因是Oraclize是一个独立的实体,导致逻辑上应该完整的一个操作被分割成了两个事务。因此,通过Oraclize与链下数据交互时只能更加小心,代码编写需要更加谨慎。
如何在自己的合约中使用oraclize服务
在区块链中正确部署了地址解析器和连接器之后,可以使用node bridge --oar标志(生成最新的oar地址)或使用node bridge --instance latest。如果你不使用确定性OAR,则还需要使用生成的新地址解析器更新合约构造函数。
1.在自己的合约中导入usingOraclize.sol合约
从github上下载oraclizeAPI_0.4.sol合约,并将该文件重命名为usingOraclize.sol,放在你的contracts文件夹中。然后通过
在自己的合约中导入usingOraclize.sol合约。
2.在构造函数中添加地址解析器OAR
例如:
注意:选择的地址将用于部署Oraclize合约,确保不要在同一地址部署你自己写的使用了Oraclize的合约。
3.发送查询
在Oraclize服务中,你必须向Oraclize智能合约发送查询,Oraclize接收你的查询并进行相应的请求。 一旦服务从API接收数据,他们就会在智能合约中调用回调函数,你可以访问和处理所请求的数据。
以上代码用于检索1个ETH的当前美元价格。oraclize_queryfunction用于通知Oraclize有关第三方API。在_callback函数中,第一个参数是请求的ID。 第二个参数是请求的结果。
向Oraclixe发送一个查询时
1.如果第一个实参是字符串,就表示数据源,第二个实参是数据源的输入条件
2.如果URL数据源后只有一个字符串实参,表示向此URL发送HTTP GET请求
3.如果URL数据源后有两个字符串实参,表示向此URL发送HTTP POST请求,第三个实参即为POST请求的内容,例如
1)如果第一个实参是数字,就表示在预约查询,比如第一个实参86400,则表示Oracize在看到此查询86400s(24h)后开始查询。
2)如果最后一个实参是数字,它表示自定义的gasLimit,默认为200000,不得低于200000。
3)没有花费完的gas将被返还给Oraclize,而非用户。
区块链安全公司WF曲速未来提醒:来自任意以太坊地址的第一个Oraclize查询调用都是免费的。
(作者:区块链安全档案,内容来自链得得内容开放平台“得得号”;本文仅代表作者观点,不代表链得得官方立场)
评论(0)
Oh! no
您是否确认要删除该条评论吗?