区块链公链介绍与安全问题分析:以 Ethereum 为例

896 阅读17分钟

本文基于博主所选修的西安电子科技大学 杨力老师的《计算机安全导论》课程大作业修改而来。
本文介绍经典的公有链,一些概念在私有链、联盟链场景下不适用。

区块链简介

概述

区块链,在最本质上而言,是一个不可信环境下的去中心化分布式数据库。其最大特色,在于其能在完全无信任、可能受到任何种类攻击的公网环境下建立并维持一个完全开放的数据库系统,该系统中每个节点(也就是参与区块链网络维护的参与者)通过 P2P 的分布式网络连接,它们之间的关系完全对等,不存在拥有更高权限的超级节点。这些节点可以通过被称为“挖矿”的机制实现对数据库读写操作的应用生效,并要求网络中其他的区块链节点同步该操作,节点之间以点对点的通信方式扩散消息,逐步进行状态的更新和同步,实现整个网络所共同维护的状态的最终一致。

网络中的所有节点都会存储区块链网络在创建时的初始状态(区块链中称之为“创世 Genesis ”),并全量备份存储自那时起到当前时间的所有读写操作记录,这些读写操作的记录被称为“交易( Transaction )”,一组交易会被打包成一个“区块( Block )”,区块和区块之间通过一个 Hash 值作为指针进行连接,这个 Hash 指针连接起来的交易数据包组成的链表,就是区块链的数据结构。

这个包含了自区块链网络创建以来所有交易的链表结构,就是所有节点共同维护的“区块链”。

区块链最成功的应用是数字货币。其特点在于,数字货币应用在这个数据库中存储的是账户信息和转账信息等。这样一个存储账户和转账记录的数据库,自然就成了账本,这也是区块链有时被称为“账本”的原因。

接下来将以经典的以太坊区块链系统为例,对区块链技术进行介绍和分析。

以太坊存储的数据

“存储的数据不可篡改、不可抵赖”,是区块链系统最广为人知的特性之一。

以太坊中的数据可以分为两类:一类是持久性存储的数据,内容是以交易为核心的历史操作记录;另一类是暂时存储的,内容是以实时变动、更新的所有账户的数据为核心的世界状态(State)。

持久性存储的数据,即是被直接写入区块的“通过全网共识确认、无法篡改”的数据。这些数据的核心是交易(Transaction),交易记载和体现的是对世界状态变化方向的描述——它们记载了世界状态的历史前行的路径,描述了其变化的轨迹。我们可以从一个确定的创世区块——也就这个当前区块链世界的开端——追随这历史的轨迹,描绘出这世界经历过的任意时刻的总体状态。

暂时存储的数据,是那些仅仅描述当前状态,可以改变的数据。这部分数据主要是所有账户状态(账户是一个包含了用户公钥地址、余额等字段的结构)的总和,被称为“世界状态”(一般直接写作 State )。这些信息时刻准备着被用于即将发生的交易,也就是时刻等待着查询和被修改。

用银行账户的比喻,区块链中持久存储的交易数据,就相当于是银行自己保存的所有人的所有转账交易记录。区块链中的 State,就相当于是所有人每个账户的账号和最新账户余额的信息。后者可由前者进行逐步推导得来,也会随着新的交易的发生而变化,其用处之一是可以在发生新交易时直接检查账余额是否足以支付交易。

至于为什么这个所有用户的信息总和被称为“状态”,这和以太坊的状态机模型有关。

以太坊的状态机模型

在以太坊区块链系统中,所有账户的数据总和被称为“世界状态 ( World State )”,每次对数据库进行的增改操作被称为“交易(Transaction)”,以太坊中所有账户状态随着交易操作的生效而发生改变。

在以太坊中,“世界状态”一般被简写为 State ,其是以太坊中所有账户信息的集合。账户信息的主要内容是账户的公钥地址( Address )和余额( Balance )。

区块链系统运行的过程,就是世界状态随着交易的生效而不断改变的过程。
如上图所示,每个 State 都是当时所有账户的信息之和,State 会在 Transaction 的执行生效后发生改变,实现状态的转移。图中的 sendTransaction(from, to, value) 是以太坊的转账(发送交易)操作,具体运行时,网络维护节点(矿工)会将一组交易打包成为一个区块,经过验证后批量执行生效,并将这种操作向全网所有节点进行扩散和同步。

也就是说,每次状态转移都是由一个区块所包含的所有交易批量生效推动转移的。只要保证了全网所有节点中的区块链的所有区块内数据一致,就能够保证全网所有节点的最新状态一致。而区块链内容的一致,由其特殊的数据结构和共识机制共同保障。

以太坊的区块链数据结构

区块链这个名字本身就是对区块链数据结构的准确描述:区块链就是区块(Block)+链(Chain),最经典的区块链数据结构是一个用哈希值作为“指针”的链表。该链表的“指针”需要通过对区块内数据的内容进行 Hash 运算生成,因此对区块内数据内容的修改将引起指针值的不匹配,导致链表无法正常连接。

在以太坊中,一个区块(Block)由区块头(Block Header)和区块体(Body)组成,区块体中存储区块头中存储了上一个区块的 Hash 值,其扮演类似内存中链表的指针的角色,将一个个区块连接起来。 每当一个以太坊节点收集到足够的交易,该节点就会将这些交易打包成一个区块,连接到已有的区块链上,并向其他节点发送该区块、要求同步。其他的每个节点接收到新的区块并验证该区块及内部所有的交易均合法后,会执行该区块中打包的所有交易,对本地的 State 进行修改,将该块连接到自己本地维护的区块链尾部,并向其所知的其他节点传递该新区快。当以太坊中大多数节点都接受一个新区块后,整个以太坊区块链系统就实现了整体状态的更新。

区块链面对的安全挑战及解决方案举例

区块链作为一个复杂而又常常与资产挂钩的系统,面临着诸多安全挑战。本文以共识问题、智能合约问题、矿池算力霸权问题为例,进行简单介绍。

共识问题(一致性问题)

对于所有的分布式系统而言,一致性都是系统的核心问题。在区块链中,维持全网节点数据一致性的过程被称为“共识”。

相较于其他的分布式数据库,区块链最大的特色,就在于其能够在共识机制的支撑下,在开放的不可信环境下稳定运行——网络中可能出现任何状况,如时时刻刻都可以有节点加入和退出,网络状态随时可能出现波动,任何时刻都可能受到攻击。但大型的区块链网络(如比特币、以太坊等主流公有链)通过巧妙的共识、激励机制设计,实现了非常强大的保证自身数据安全的能力,让庞大的区块链网络实现最终一致性。这也是这些主流公有链上数字货币的币值可以长期保持在较高的水平上的必要条件之一。

在区块链中,所有参与网络维护(即,挖矿)的节点都会对网络建立以来的所有区块数据进行全量的备份存储,这相当于所有人都保存了一份账本的副本,当所有参与者中的大多数人是希望维护网络稳定运行的善意参与者时,就能够保证在区块链网络上传播和接受的正常请求都是针对正确的账本进行的,也就能得到正确的响应,网络整体也就能维持正常运行。

节点之间新增加的区块数据出现不一致的情况被称为“分叉”,以太坊使用了 PoW(Proof of Work,工作量证明)和 GHOST 协议来解决以太坊网络中的分叉问题。

GHOST 协议和 PoW 挖矿两者是相辅相成的关系,前者用于确保网络的统一(防止分叉),而它的安全性又由后者保障。

GHOST , Greedy Heaviest Observed Subtree

实际上,以太坊网络时时刻刻都在分叉——截至本文写作的2020年12月,全网以太坊节点已经超过11000 个。以太坊网络每十余秒会出一个新块,同一秒内超过一个矿工挖到合法区块的情况非常常见(或者说,几乎必然会发生)。也就是说以太坊主链每个时刻都有数个合法的下一区块可选,即存在着朝向数个方向前进的可能性,网络中的节点也都会收到不同的人广播的、内容不同但全部合法的下一区块——这时就需要节点来想办法确定“哪条路才是主链所应该前进的道路”。

以太坊解决问题的方式,就是使用 “GHOST 协议”:最大贪心子树协议。

由于时时刻刻网络都在分叉,所以对于网络中的每个节点而言,其自身所维护的区块链结构的最末尾都会成为一棵树,这棵树上延伸出数个子树,这些子树的叶子节点都是合法的下一个区块。 而由于整个区块链网络都要向着最多算力所在的方向前进——使用 PoW 共识机制的区块链系统有一个前提假设,就是“善意的人”应该占所有人中的大多数,那么也就可以假设善意的参与者占有更多的算力。那么既然善意的人加起来的算力总是更大,那么这些参与者在PoW机制中算块的速度就会更快。这就意味着这些参与者集中的方向就会以更快的速度产生更多的区块,这些人所在的子树延伸的也就更快更长——因此,我们也就可以认为,区块更多、延伸的更长的方向就是正确的方向,即主链方向。

所有的节点都可以通过检查这棵树上最顶端的区块的区块号(区块头中的一个字段,表明该块在链上的次序)来实现寻找这条最长的主链的目标。节点也就将会选择它收到的数个区块中区块号值最大的那个块所在的方向为自己的方向。

当网络中大多数的节点都“默契”地选择了同一个子树,网络也就在这条链上实现了一致。

PoW 挖矿

PoW 挖矿,是每个节点构造区块所必须进行的工作。该工作有一个特点,就是构造该证明需要消耗大量的算力,而验证证明是否真实则非常简单。 PoW 必然导致这样一个结果:算力越大,挖出区块的速度越快。

想要篡改整个区块链网络的数据,唯一的攻击方法就是朝着攻击者想要的方向进行网络分叉——比如攻击者可以准备这样一条新链:在这条链中,攻击者的账户凭空增加了 10000 个以太币。一旦攻击者让这条他自己准备的假链成功被网络接受为真正的链,则攻击成功。

加上上面的GHOST一起来考虑,我们不难想到:如果想要网络分叉(成功实施攻击),攻击者就需要在自己设置的方向上比所有人都挖得更快,这样他这条假链才能够被其他多数节点的 GHOST 协议接受,专门构造的假链才能成为事实上的全网接受的真链。

PoW 就是通过极大地提高“挖得比大家更快”的成本来确保网络安全。

PoW 用于确保整个网络只有一个前进方向——算力最强的方向。人多力量大,我们上文中假设了诚实的节点要比恶意节点多得多——虽然诚实节点的算力不一定强,但是在参与者非常多的情况下,我们可以大致认为节点越多算力越强。

因此,小规模的尝试篡改数据的攻击很难成功——如果想要自己节点就能打败大多数节点,就需要让自己节点的算力大于数量占优的诚实节点。当恶意节点的算力超过全网51%的时候,篡改数据的攻击就能得逞了——这就是所谓的“51%攻击”。然而在实际场景下,这样为了攻击网络而准备过半算力产生的成本会高于可能的回报,该攻击是得不偿失的。

智能合约安全问题

以太坊是比特币之后最成功的区块链项目,也是目前全世界币值第二的项目,其开创性地引入了支持“智能合约( Smart Contract )”的以太坊虚拟机(Ethereum Virtual Machine),展现出了区块链能够构建支持数字化信任应用的潜力,大大扩展了区块链应用的想象空间。

一个智能合约就是一段代码,代码的具体功能由开发者设计。这段代码会被以一种名为“合约账户”的方式部署在区块链系统上,之后只需使用一些参数向该合约账户的地址发送交易即可触发这段代码的执行。

EVM 是一个图灵完备的虚拟机,其一般作为一个必要组件内置在以太坊节点客户端中。在以太坊节点处理交易时,若发现该交易调用了一个智能合约,节点就会启动以太坊虚拟机并传入合约的字节码,随后 EVM 就会开始执行智能合约代码所定义的过程。

由于区块链与生俱来的“价值网络”属性,最适合运行在以太坊网络中的智能合约基本都是与以太币有深入联系的——也就是说,智能合约代码往往都会与“钱”相关,应用往往都涉及到虚拟货币募资以及转移。因此,智能合约的安全问题可以说是区块链应用最核心的问题之一,若智能合约存在漏洞则可能造成极其严重的后果。以太坊历史上最著名的 “The DAO” 事件,便是黑客利用了该项目智能合约代码中的一个递归漏洞,盗走数额巨大的以太币引起的。该漏洞当时威胁到了超过 1.5 亿美元的以太币。这次事件最终也导致以太坊实行硬分叉,原 ETH 分裂为 ETH 和 ETC,该事件也引起了关于“区块链到底应该怎样”的哲学讨论。

在那之后,各种基于智能合约的第三方项目代币安全事件也层出不穷,比如 2018 年,黑客利用 BEC、SMT 项目的智能合约中的整数溢出漏洞,凭空创造巨额代币并进行抛售,导致项目币值归零。

要解决该类问题,需要开发智能合约的项目方在技术方面加强投入,降低产生漏洞的概率。并需要在项目的开发过程中引入有更强技术背景的合约安全审计公司对合约进行充分的检查和测试。

矿池算力霸权问题 —— 51% 并非不可能

矿池是一种“矿工组织”:PoW 挖矿难度逐渐升高,现在已经到了一般个体矿工能够掌握的算力很难成功出块的程度。因此,拥有挖矿的设备的用户可以选择加入一个矿工组织(矿池),来和矿池中的所有其他矿工共同挖矿,并根据贡献共同分享整个矿池成功出块后的收益。矿池的整体算力越强,矿池出块的概率就越大。但矿池的产生和壮大也导致了算力的过度聚集。 如上图所示(来自 etherscan.io ,2020 年 12 月数据 ),前三大矿池的算力占比超过全网算力的 56.5% 。这意味着如果大矿池的合谋分叉并非完全不可能,而这会为分叉的公链生态带来巨大影响。

事实上,类似的事件已在 2018 年发生过了。

2018 年,比特大陆支持的 BCH 主要开发团队 Bitcoin ABC 与澳本聪( CSW )控制的 nChain 开发团队在决定 BCH 未来走向的问题上发生矛盾,随即整个社区分为两派并展开了一场“分叉大战”。此次大战最终以 BCHABC 的胜利告终。

虽然区块链可以在技术上去中心化,但以资本为基础的算力中心化却似乎仍然不可阻挡。今后矿池、链上大型组织和区块链的关系将走向何方,还有待进一步的观察和研究。

总结

本文以以太坊为例,从设计、数据结构等方面,简要介绍了区块链的原理。并简要介绍了共识、智能合约、矿池算力霸权等安全问题。 近年来,区块链相关概念常常成为引人注目的焦点,也不乏各种尝试将区块链结合进现有场景或创造全新应用场景的研究。但实际上,到目前为止仍然没有出现一款除了数字货币之外的“杀手级”区块链应用。笔者认为,区块链技术无论是在技术上还是应用方式上都还处于相当早期的发展阶段,目前区块链面对着贯穿技术、社会、经济、政治、法律甚至道德伦理等各层次、全方位的问题和挑战。