干货 | 以太坊智能合约安全

ETHButterfly2018-05-13 21:03:08  阅读 -评论 0  阅读原文


引言


智能合约就是自主执行的合约,其条款是用代码规定的。

虽然这个概念已经存在一段时间了,但至少从1996年Nick Szabo提出了这一概念以来,直到图灵完备的以太坊区块链来临,智能合约的使用才变得普遍。

以太坊的智能合约存在于合约地址里,能以交易命令来调用。用代码编写并存放在不可更改的公链上的合约执行起来会产生一定的风险与安全问题。我们将会在本文中讨论这些问题和可能的缓解措施。

代码即法律?


对智能合约理念的字面解释造成了"代码即法律" ( "Code is Law" ) 的范式理解,意思是那些智能合约具有约束力,并被诠释为合法文件。所有意识到无法创建完全无错代码的软件工程师在想到计算机程序具有合法约束力的时候,手心都会捏一把汗。这里存在很多明显的问题:

  1. 代码有漏洞。写无bug代码是一件非常困难的事情,即使做好了所有可能的预防措施,在相当复杂的软件中也总会存在意想不到的执行路径或者可能的漏洞。
  2. 法律合约也需要解释与仲裁。创建毫无漏洞法律合约是非常困难的。在任何大型合约中,拼写错误可能出现,一些条款需要解释和仲裁。这就是为什么在出现争议时我们需要法庭。如果在某个法律合约中,40页中有39页标定的销售价格为100美金,而在某一页上的价格中多了个"0",法院将以"合约精神"为准进行裁定。而计算机只会执行写好的条款,区块链的不变性增加了这个问题,因为合约无法轻易修改。
  3. 软件工程师不是法律专家,反之亦然。起草一份好的合约需要与编程不同的技能,一名能够编写非常完善计算机程序的人员不一定会写法律合约。

两起著名的利用智能合约漏洞的事件

The DAO 攻击

这件事很多人都早已谈了许多,我们就不在这重复了。您可以在这里找到关于攻击和善后的完整概述。

简单来说,在 2016 年 6 月,一名黑客企图转移一大笔众筹资金 (350 万个 ETH, 占当时ETH总数的15%)至他自己的子合约,这笔资金被锁定在该子合约中 28 天,因而大家要与时间竞赛寻找解决方案。

这事件要注意的重点在于,攻击者是通过使合约以意料之外的方式运行而发起的攻击。这个事件中,攻击者利用了 可重入漏洞( Reentrancy Vulnerabilities )。我们将会在这篇文章中对可重入进行深入讨论。

黑客攻击Parity事件

事实上,这是第二次 Parity 所提供的的多重签名钱包合约受到黑客入侵了。众多创业公司使用的多重签名钱包的逻辑大多通过库合约实现。每个钱包都包含一个轻量级的客户端合约,连接到这个单点故障(译注:即上述库合约)。

-Parity 多重签名钱包结构-

这个库合约中存在一个重大的漏洞,问题在于其中一个初始化函数只能被调用一次。

2017年11月,一名男子通过实施合约初始化,将自己变成了合约所有者。这允许他调用所有者才能调用的 函数,他利用这一特权调用了以下的函数:

// kills the contract sending everything to `_to`. function kill(address _to) onlymanyowners(sha3(msg.data)) external { suicide(_to); }

这相当于一个能使合约无效的自毁按钮。调用这个函数会导致客户合约的所有资金有可能被永久冻结。

直到撰写本文之时,该事件到底是黑客造成的故意攻击还是意外仍然是个谜,尽管肇事者声称这是意外行为。

两次攻击都说明了即使是由以太坊生态系统的大佬来写相对简单的合约,也容易出现基本的错误,带来严重的后果。

已知的漏洞与陷阱

私钥外泄

使用不安全的私钥纯粹是用户的失误,而不是一个漏洞。然而,尽管如此,我们还是要指出来,因为私钥外泄总是意外地发生,有些玩家专门从不安全的地址中窃取资金。

把开发地址(如 Ganache/TestPRC 使用的地址)用于生产的事情经常发生。这些地址是由公开的私钥生成。一些用户甚至无意识地把这些私钥导入到钱包软件,因为他们使用 Ganache 的种子词(seed words)生成了相同的私钥。攻击者则监视着 TestPRC 地址,不管多少数量的以太币只要转移到以太坊主链上的 TestPRC 地址都会立刻消失(在2个区块内)。一项有趣的研究对这一十分有利可图的"清扫(sweeping)"活动进行了调查,并发现每个清扫者(sweeper)的账户都设法累积了高达2300万美元的资金。

可重入与竞态条件(Race Conditions)

如果一个函数在执行完成前被调用了数次,发生意料不到的行为时,可重入漏洞就可能出现。

让我们看看下面这个函数,它可以用于从合约中提取调用者的总余额:

mapping (address => uint) private balances; function payOut () { require(msg.sender.call.value(balances[msg.sender])()); balances[msg.sender] = 0; }

调用 call.value() 会导致合约外部代码的执行。若调用者是另一份合约,这就意味着合约回退措施的执行。这可能会在余额调整为 0 之前再次调用 payOut(), 从而获得比可用资金更多的资金。

这种情况下的解决方法就是使用替代函数 send() 或 transfer() ,后两者函数能为基础运作提供足够的 Gas,而想要再次调用 p*ayOut()* 时 Gas 就不足了。

若合约含有两个共享状态的函数,那么不需要重复调用函数也可能会发生相似的竞态条件(Race Conditions)。因此,最好的做法是在转账前更改状态,即转移资金前,在上述代码中把余额设为 0。

The DAO 攻击利用了该漏洞的一种变体。

下/上溢

余额一般用无符号的整数表示,在 Solidity 语言中通常为 256 位数字。当无符号整数上溢(overflow)或下溢(underflow)时,其数值会发生明显变化。让我们看看下面一个比较常见的下溢例子 (为了清晰一点我把数字缩短了):

0x0003 - 0x0004 -------- 0xFFFF

这里很容易看出问题,减去一个比可用余额大的值便导致下溢。得到的余额是一个很大的数字。

还要注意的是由于舍入误差(Rounding Errors),在整数中算术分割(Arithmetics Division)是很麻烦的。

解决方法是时刻对代码进行下溢、上溢检查。使用安全数字库能协助检查,比如 OpenZeppelin 的 SafeMath。

交易顺序假设

交易进入未确认的交易池,并可能被矿工无序地包含在区块中,这取决于矿工的交易选择标准,有可能是一些旨在从交易费中获取最大收益的算法,但也可以是其它任何标准。因此,打包在区块中的交易顺序与交易生成的顺序完全不同。因此,合约代码无法对交易顺序作出任何假设。

因为交易在记忆池(Mempool)是可见的,其执行是可预测的,所以除了合约执行出现意外结果的情况,还有一个可能的攻击面。交易打包中可能出现的一个问题就是,延迟某个交易可能被流氓矿工用作个人利益。事实上,能够在交易执行前意识到某些交易(的存在)对任何人来说都是有利的,而不仅仅是矿工。

对时间戳的依赖

时间戳(Timestamps)是由矿工生成。因此,合约不应该让关键操作依赖于区块时间戳,例如把时间戳用作一个生成随机数的种子。Consensys 在他们的指导手册中给出了"12分钟规定",表明如果你依赖时间戳的代码能够处理 12 分钟的误差,那么使用block.timestamp 是安全的。

短地址攻击

Golem team 揭露了一个有趣的攻击,详情请看这里。该漏洞影响了 ERC20 代币传输和一些类似的合约,该漏洞的问题在于交易字节代码可以是任意大小,而以太坊虚拟机(Ethereum virtual machine,简称EVM)会在其尾部缺失的字节填充0。

实施该攻击需要找到一个以十六进制(hex)形式表示且结尾为若干个 0 的地址,并在提币请求中省略这些结尾的 0。当该合约发起一个转账请求时,短地址被插入,其余的交易字节代码被移位。

举个例子,省略结尾的两个 0 会导致交易数据中地址之后的字节发生 1 个字节的移位。地址后面是交易数据中的参数,通常是无符号的前置 0 的 256 位整数。这些前置的 0 会移入地址字段,使地址有效并确保交易目的地是正确的。

参数字段中一个字节的移位也很容易导致提币量变为原来的256倍。在EVM用 0 填充缺失的结尾字节后,交易成功,然后转走 256 倍的金额。

因此,利用省略两个十六进制0的地址的漏洞使攻击者可以从一个余额为 1000 个代币的账户中提取 256000 个代币,以此类推。省略 4 个结尾的 0 则是 2^16 倍。

为了避免这种攻击,你的合约应该验证地址。

拒绝服务攻击(DoS Attacks)

有时通过使合约交易超过能够包含在一个区块中的最大 Gas 量,来迫使合约交易失败。在这篇拍卖合约的解读中解释了这个经典例子。迫使合约退还大量没有接受的小投标会增加 Gas 消耗量,如果能耗超过了区块 Gas 上限,那么整个交易失败。

这个问题的解决方法是避免许多交易调用可能由相同的函数调用引起的情况,尤其是如果调用次数会受到外部影响。

推荐的付款模式是让客户请求转账,而不是一次性转账出去,如 Solidity 官方文件所述。


缓解措施与结论

为了强调"代码即法律"这一范式理解的危害,本文我们阐述了可能发生的漏洞以及过去攻击者是如何利用这些漏洞的例子。

最近的历史事件表明在公链上执行图灵完备的智能合约是危险的,其安全性远不足以取代传统法律系统的语言准确度与解释和仲裁空间。

但这并不意味着我们应该抛弃智能合约。智能合约是非常有用的工具,能开发出有趣的应用程序。然而,我们不能认为智能合约能取代具有法律约束力的合约,它只是用于自动化的补充工具。

另外,我们应该做好预防措施去避免漏洞:

  • 使用开放的资源与社区接受的库合约的实质标准 (de facto standards),例如 Open Zeppelin's contracts。
  • 使用推荐的模式与最优操作指导手册,例如 Consensys 提供的。
  • 考虑由信誉好的供应商审核您的智能合约。

原文链接: https://medium.com/cryptronics/ethereum-smart-cont...
作者: Stefan Beyer
翻译&校对: 杨哲 & Elisa

哲妹

在探索中增值

本文由作者授权 EthFans 翻译及再出版。


声明:链世界登载此文仅出于分享区块链知识,并不意味着赞同其观点或证实其描述。文章内容仅供参考,不构成投资建议。投资者据此操作,风险自担。此文如侵犯到您的合法权益,请联系我们kefu@lianshijie.com

参与讨论 (0 人参与讨论)

相关推荐

比特币减半和以太坊2.0将为加密矿工带来巨大变化

比特币减半和以太坊2.0将为加密矿工带来巨大变化

在比特币减半和冠状病毒大流行来临之后,私人矿工们受到了冲击,但大型厂商也受到了影响。

以太坊2.0技术浅析

以太坊 2.0网络启动协调员Danny Ryan也在论坛中初步宣布,以太坊2.0最终测试网预计将于8月初正式启动测试。我们应该在以太坊2.0正式上线前对它的功能特性进行了解,更好的迎接区块链的新浪潮。

比特币有什么缺点?

1.交易平台的脆弱性。比特币网络很健壮,但比特币交易平台很脆弱。交易平台通常是一个网站,而网站会遭到黑客攻击,或者遭到主管部门的关闭。2.交易确认时间长。比特币钱包初次安装时,会消耗大量时间下载历史交易数据块。而比特币交易时,为了确认数据准确性,会消耗一些时间,与p2p网络进行交互,得到全网确认后,交易才算完成。3.价格波动极大。由于大量炒家介入,导致比特币兑换现金的价格如过山车一般起伏。使得比

业务中使用区块链的四种方式

业务中使用区块链的四种方式

暴走时评:区块链是一种支持像比特币这样的数字货币的公共分类帐本,并且正改变着我们的业务方式。一旦那些对匿名交易,甚至是秘密交易感兴趣的人接纳了这样一种鲜为人知的工具,加密货币就会日趋成为主流。 区块链是一种支持像比特币这样的数字货币的公共分类帐本,并且正改变着我们的业务方式。一旦那些对匿名交易,甚至是秘密交易感兴趣的人接纳了这样一种鲜为人知的工具,加密货币就会日趋成为主流。越来越多的个人和企

区块链:法定数字货币技术路线的必然选择

区块链:法定数字货币技术路线的必然选择

在人类发展史上,货币的进化从未停止。从物物交换,到金属铸币,再到纸质货币,以及当前正在发展的数字货币正在向着越来越便捷的方向进化。 比特币的出世起初并未带来轰动,但是最近几年其价格惊人的爬高创造出了一个个造富神话,引起各国政府及监管机构的关注。虽然金融专家普遍认为它只是一种资产,而非货币,但是,其背后的区块链(Blockchain)技术引起了包括各大金融机构、政府、企业及学术界的浓厚兴趣,未

用区块链记录证书,证明真伪,墨尔本大学迈出了第一步

用区块链记录证书,证明真伪,墨尔本大学迈出了第一步

墨尔本大学宣布发起区块链认证和审核计划,允许通过一种隐私、安全且持久的方式验证学生的证书。 墨尔本大学正在试验一个区块链记录维护项目,允许接收者(即学生)存储他们的证书,出于核验目的,第三方也能访问这个系统。Learning Machine是这个发布系统的开发者,他们采用的是麻省理工媒体实验室(MIT Media Lab)在2016年提交的Blockcerts开源代码。 墨尔本大学副校长格雷

日本IT巨头富士通联合日本“三大行”开发区块链p2p资金转移系统

日本IT巨头富士通(Fujitsu)与三家大型银行已经宣布计划试点一项基于区块链创建的点对点资金转移系统。 通过与日本三大行——瑞穗金融集团,三井住友金融集团和三菱UFJ金融集团——的合作,富士通将现场试验一种基于云的区块链平台,用于在个体之间发送资金,并开发一款智能手机APP来提高这个系统的可用性。 从理论上讲,这个平台将把三大行的客户法定货币账户与这个区块链系统相连接。客户然后将能够使用这

动画科普:什么是比特币?

动画科普:什么是比特币?

比特币(Bitcoin,简写BTC)概念由中本聪(化名)提出,是一种点对点、去中心化的数字资产;2009年,中本聪打包了第一个区块,并获得50枚比特币的挖矿奖励,挖矿奖励每4年减半一次,按此计算,比特币预计2140年发行完毕,总量为2100万枚。 随着比特币的发展,比特币逐渐受到认可:德国为全球首个接受比特币支付的国家;微软、戴尔等知名企业也纷纷接受比特币支付。 举个栗子,你能直接用比特币买到

麦妖榜
更新日期 2019-09-03
排名用户贡献值
1牛市来了30910
2BitettFan24187
3等待的宿命23810
4区块大康20369
5六叶树20310
6linjm122719429
7天下无双16192
8lizhen00215280
9让时间淡忘14586
10yelanyi050511349
返回顶部 ↑