Neo如何抵御“日蚀攻击”?

前言
居善地,心善渊,与善仁,言善信,政善治,事善能,动善时。
背景
区块链常见的攻击主要有,延展性攻击、51%算力攻击、DDoS攻击、女巫攻击或日蚀攻击、粉尘攻击。这里就不一一介绍了,主要来聊下「日蚀攻击」。

日蚀攻击(Eclipse Attack)是一种针对点对点网络(p2p)特殊拓扑结构的攻击手段。

Neo如何抵御“日蚀攻击”?

大家都知道日蚀是一种天体物理现象,月球在白天的时候运行到地球与太阳之间,遮住太阳光,形成日蚀。日蚀攻击取其意相,在网络中通过恶意网络连接将目标节点从网络连接环境中隔离,使目标节点无法获取网络上的正常数据,就好像日蚀下地球无法获取太阳光,故名“日蚀攻击”。
针对传统P2P网络的日蚀攻击由来已久。而针对区块链网络的日蚀攻击首次出现于2015年的信息安全顶级会议USNIX。波士顿大学的 Ethan Heilman在其论文 《Eclipse Attacks on Bitcoin’s Peer-to-Peer Network》中,分析了日蚀攻击针对区块链网络的手段可行性和可能造成的严重后果。
– 论文地址 –
https://eprint.iacr.org/2015/263.pdf

Neo如何抵御“日蚀攻击”?

在比特币网络中,目前理论上几乎唯一存在的攻击手段是51%算力攻击,虽然这种攻击手段在别的基于PoW共识算法中已经被成功实施了很多次,比如以太经典的51%算力攻击。
– 「以太经典51%算力攻击」原文地址 –
https://bravenewcoin.com/insights/etc-51-attack-what-happened-and-how-it-was-stopped

Neo如何抵御“日蚀攻击”?

但在比特币网络里却从来没有过被人成功实施过的迹象,毕竟花费数亿美元的代价去实施攻击,无论怎么看都是得不偿失的。但通过日蚀攻击,攻击者可以不对整个网络进行攻击,而是针对特定的节点,比如攻击交易所,这样的攻击成本将远小于51%的算力需求。
在实施日蚀攻击时,攻击者可以向受害者发起大量的网络连接的建立请求,让自己成为目标节点的Peer node。通过这种手段,一旦受害者所有的peer node都变成由攻击者控制的节点,受害者在区块链网络的所有input和output都将收到攻击者的监视和控制。
一旦控制了受害者的所有区块链网路通信,攻击者就可以拦截正常区块链网络里同步的交易,新区块等信息,转而向受害者广播自己挖出的新区块,而由于受害者无法获取正常网络的区块信息,攻击者将不再受限于攻击正常网络所需的51%算力,而只需要掌握比受害者多的算力即可完成攻击过程。
针对普通节点的日蚀攻击可使目标节点的算力无效,挖出无效区块,相应地使自己的算力在区块链网络中的占比增加。而针对交易所的日蚀攻击则可能通过一个单独对交易所发起的转账交易或者提款交易而在交易所节点中完成双花攻击或者直接窃取交易所持有的加密货币。
来自peer node的网络封锁
以我的了解来看,想发起日蚀攻击,攻击者就必须用自己控制的节点完全取代受害者在区块链网络中的正常peer node,否则任何一个可能的链接都会使得受害者接收到正常的区块和交易。此外,攻击者应该有能力构建伪造的新区块并且可以通过受害者节点的验证,否则,仅仅是将目标节点从区块链网络中隔离开来,攻击者所能获得的收益将无法最大化。
基于以上,我们来分析对Neo网络发起日蚀攻击的可能性。
先来看下将Neo节点在网络上进行封锁的可行性。关于网络部分的更多内容,欢迎阅读《Neo从源码分析看网络通信》。
-《Neo从源码分析看网络通信》 –
https://my.oschina.net/u/2276921/blog/1622015
除了从Neo服务器获取之外,还能以主动获取的方式来获取网络节点,即将网络节点的请求广播给所有与本地节点建立连接的节点,通过已连接远程节点的节点列表来实时收集整个网络中的节点信息。 
分析Neo的网络机制,就能知道Neo在网络通信这块能够直接跟目标节点建立通信,这是一个好的开头。接下来,再看看其存在的潜在限制,是否能通过单一节点来发起大量的网络连接以请求阻塞目标节点。
通过分析源码,我们在src.neo.Network.P2P.ChannelsConfig.cs 里看到了Neo针对peer节点IP的限制,同时也有针对最大链接数量的限制。但这是好事,至少意味着隔绝节点的工作量是有上限的。
/// <summary>
/// Max allowed connections
/// </summary>
public  int  MaxConnections { get; set; } =  Peer.DefaultMaxConnections;
/// <summary>
/// Max allowed connections per address
/// </summary>
public  int  MaxConnectionsPerAddress { get; set; } =  3;
但是对同一IP的链接限制也意味着没办法仅通过一台机器发出大量链接请求来实施廉价高效的攻击。从攻击者角度来说,这很不友好。更不友好的是,Neo在初始化的时候,会先加载一个seedlist作为初始peer nodes的候选人。
– 源码位置 –
src.neo.Network.P2P.LocalNode.cs
private  readonly  IPEndPoint\[\] SeedList  =  new  IPEndPoint\[ProtocolSettings.Default.SeedList.Length\];
而这个SeedList里明显不会有攻击者的地址。
“seed1.neo.org:10333”,
“seed2.neo.org:10333”,
“seed3.neo.org:10333”,
“seed4.neo.org:10333”,
“seed5.neo.org:10333”
这里就会出现麻烦,因为我们没办法在不直接攻击目标节点或者DNS的前提下让目标节点和这些seedlist断开链接。
从共识入手
接下来,我们再来分析下Neo的共识机制。更详细的内容,欢迎阅读《Neo从源码分析看共识协议》。
Neo采用的是dBFT共识机制,在dBFT共识过程中,并不是所有的节点都有参与共识的资格,而是需要投票选举出一票议员(目前还是官方指定)。一票议员的列表在每一个节点中都有备份,所以想要把自己伪造成议员是不太现实的。在共识过程中,新区块由议员轮流化身议长主持生成,并需由超过2/3的议员验证签名确认后才能生效。在普通节点同步新区块的时候,是会验证区块的签名,如果签名数据不合法,那么新区块就会被无情拒绝。
dBFT的这种共识结构对日蚀攻击本身是不友好的,当然,你也可以说是更安全的。因为议长生成区块议员进行验证的机制本身就意味着,即使我们成功把目标节点隔离开,那么也没办法生成合法的新区块。因为攻击者本身不是议员,没机会生成新区块。而且即使攻击者是议员,又假设刚好是议长,这时候情况会稍微乐观点,但是想要往下进展依然很难。
来自恶意议员的协助
我们假设议员里有刚好1/3,1个议员统一协助我们发起攻击,并且无视Neo对peer节点的一系列限制。
情况看似一片大好,我们拥有了这么多的卧底,哪怕我们再拉一个人加入我们,我们就可以光明正大的给Neo使绊子了,但我们偏不,我们就要这种刚刚好的感觉。但是真的前景光明么?
由于每个共识周期的区块是在共识周期内的视图里生成的,所以我们可以在共识周期里重置视图的地方看到,对于新生成区块其实是由一个多签账户来生成的,这个多签账户就是通过全体议员中超过2/3议员签名来验证通过的。
– 源码位置 –
src.neo.ledger.Blockchain.cs
public  static  UInt160  GetConsensusAddress(ECPoint\[\] validators)
{
              return  Contract.CreateMultiSigRedeemScript(validators.Length  – (validators.Length  –  1) /  3, validators).ToScriptHash();
}
由于我们的议员数量无法达成生成新区块的必要条件,所以除了已有的卧底之外,我们还需要添加新议员进入我们的阵营。但是通过“合法”手段获取新的节点似乎是一件不可能完成的任务。
首先,在Neo网络中添加新议员是需要经过选举过程的,这个过程中的所有交易都需要经过已有的超过2/3议员的验证才能通过,即先要通过选举增加攻击者的实力,才能“光明正大”地攻击Neo。因此,对Neo网络实施日蚀攻击似乎是不现实的。
总结
本文从Neo源码的角度,一方面分析了日蚀攻击的攻击手段和可能造成的后果,另一方面也探索了面对日蚀攻击的时候Neo系统本身的稳固性。
本文是关于区块链安全的科普性文章,部分内容可能不符合专业性,严谨性,酌情饮用。作者实力所限,文中难免疏漏,望不吝交流指点。