首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

区块链防黑客攻略

区块链防黑客攻略

4月22号, 美蜜链BEC市值暴跌为零,起因为发币代码里的一个巨大漏洞被黑客钻了空子。所以搞区块链开发一定要好好写代码!因为你一旦把程序放到主网上运行就不能再修改了。你可以在测试网络里做无数的测试和修改,但是一旦上了主网你就没有第二次机会。所以代码者,乃区块链之大事,死生之地也,不可不察呀。

细心的网友

那这个bug到底怎么回事呢?

简单的来说,就是一个转账函数在执行的过程中,运算发生了溢出。

红框标注出来的地方就是运算溢出的地方。这个函数是干什么事情呢?就是有一定数量的代币要同时发送给多个人。所以那一行代码就是计算你总共要发多少代币出去。当然在发送之前必须检查你帐面上有那么多代币可以用。

乍一看这个逻辑没啥毛病,但是黑客却成功转一个巨大数量值。

细心的网友

这个值究竟有多大?

57,896,044,618,658,100,000,000,000,000,000,000,000,000,000,000,000,000,000,000.792003956564819968个BEC。这个数量远远超过了发行量的总数。

细心的网友

居然成功了!这是为何?

那是因为这个值实在太大,在运算的过程中溢出,使最终结果倒退成了零。

跟我们以前小学时候学过的加减乘除不一样,在计算机里一个正整数乘以另一个正整数最后的结果有可能是比原来小。这也许刷新了各位的三观,但是你们从另一个角度想就可以理解了:首先数字本来就是一个抽象的概念。在实际运算过程中你必须给定一个范围,无穷大是不存在的。所以在计算机里用位数来控制范围,它的单位就叫bit(比特)。8bit就相当于8位,32bit就是32位,以此类推。

上图每一个格子就是1bit,只能填0或者1。 比如说32位正整数,那表达的范围就是0至2的32次方,相当于4294967296。如果是64位,那范围就更大了,可以到2的64次方。在很多编程语言里,通过用不同的标识符来区分不同的整数范围。比如32位是Integer,64位就是Long等等。

拿32位正整数来举例,如果我从0开始,每一次加1直到每一位都变成了1为止,那便达到了上限。如果这时候我再加1呢?

如上图所示,由于这个进位超过了位数上限,所以计算机自动忽略,最终的结果就转变成0。

一般对于这类运算溢出的处理,有以下几种方式:

限定输入数字的范围。通过设置一个保守的数字范围来保证输出不会超出上限。比如我们要让a×b

反向验证。具体思路就是: 如果a×b=c成立的话,那 c/b=a也能成立。同样的道理可以应用于所有的四则运算里。这个方法非常简洁优雅。因为如果a或者b过大,导致结果溢出的话,c/b=a就不成立。

这个是open zeppelin的经典做法。Open zeppelin是以太坊solidity上最好的智能合约框架,被应用在大多数发币和约里,所以它里面的四则运算库函数,也是应用最广泛的。

动态分配位数。这种方法理论上可以应对任何大数之间的四则运算,因为它可以根据具体输入来自动分配位数。比如上述情况如果32位不够用,那我们就分配33位,依次类推。所以这个方法既解决了溢出问题,又提供了最大的自由度,但是它实现起来略微复杂。Java里面的BigInteger就是这种方法的实现,在比特币的核心代码里也有广泛的应用。

区块君

除了以上的黑客攻击之外,我再来给大家介绍下其他的攻击方式以及它的应对方法。

DOS攻击:

Dos即(Denial of Service)的简称,拒绝服务。就是通过伪造多个IP地址,不断地向服务器主机发送无用数据的请求,直至网络堵塞或者崩溃。大家可以把整个网络服务想像成一个餐厅的模式,这就好比一些不法之徒堵在收营台前面不让你结账。在比特币的设计里就考虑到了DOS攻击的情况。比如引用POW的挖矿机制也是为了防止DOS。因为你要广播一个区块出去需要先进行复杂地“挖矿”,这样就让黑客发送一个区块出去消耗的算力成本很高。假设没有POW的话,那黑客就有可能在短时间广播大量的区块造成网络堵塞。还有对区块容量的限定也是防DOS的一个美妙设计。像比特币区块大小限制在1MB,即使以后扩容到2MB也是一个很小的值,所以这就避免了矿工产生大区块,里面塞满了垃圾数据,把其他结点的硬盘塞满。

渗透攻击:

如果把你把一个应用程序看成一个黑箱的话,那就是输入和输出。那用户端如果输入一些奇怪的特殊字符呢?虽然是一个黑箱,但是黑箱接受到的数据是有可能会和内部的程序发生耦合的。举个例子,如果我们要做一个查询用户银行账户余额的应用程序。客户端可以输入用户的编号(user_id)来查询。这个功能可以通过一个动态SQL语句来实现:

"SELECT accountNumber, balance FROM accounts WHERE account_owner_id = "

+ request.getParameter("user_id");

其中的"user_id"作为传递的参数是客户端所提供的。

比如客户端通过调用https://bankingwebsite/show_balances?user_id=984

来传递user_id的参数。这时候整个查询语句就是:

SELECT accountNumber, balance FROM accounts WHERE account_owner_id = 984

从而就实现了查询编号为984的用户的银行账号余额。

如果这时候有个不怀好意的黑客调用了这个命令:

https://bankingwebsite/show_balances?user_id=0 or 1=1

那最终的查询语句就变成

SELECT accountNumber, balance FROM accounts WHERE account_owner_id = 0 OR 1=1

于是最后的结果就变成查询所有用户的账号了。这就是一个典型的渗透攻击。解决这个问题的方法也很简单,你可以限定输入的类型,比如说必须要输入一个整数,否则就报错。或者你把整个数据进行编码,然后封装在一个消息里面发送出去。让他不轻易暴露在客户端。像比特币的核心代码里面,就广泛地应用了一种base64的编码模式,任何形式的数据无论是一段话,还是交易数据都加密成base64的一串编码,封装在比特币消息的payload字段里面进行传送。

细心的网友

神马是Base64?

简单来说就把二进制转换成64进制,每一位的数字范围是0到63。这个数字也叫索引,如下图所示,每一个索引对应一个字符。

通过这样的编码就能保证输出的每一个字符在可控范围以内,从而可以抵御一些特殊字符进行的渗透攻击。

区块君

关于黑客攻击的方法,今天就介绍到这里,当然还有其他不同的攻击方式,这里不一一赘述。在这个章节内,我挑选几个比较有代表性的介绍给大家,以后有机会再介绍其他的屌炸天攻击方法。

The End

区块君

以散文般行云流水的代码风格征服了各大500强公司,深信不会唱歌的作家不是一个好码农。曾经闭关研习比特币1万代码,终于修成正果,立地成佛。

搞事情啦!

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180429G1EMJ800?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券