文章目录
摘要
本文给出了一种针对比特币P2P网络的日蚀攻击。攻击者只需要有足够多的IP地址就可以切断一个被攻击节点的所有对外连接,从而可以发送任意信息给受害者进行攻击。文中还仔细研究了比特币的P2P网络,进而量化了进行日食攻击所需的资源。最后,文章还提出了针对这种攻击的解决方案,其中一些已经被集成到比特币客户端里面。
背景知识
本文发表于2015年的USENIX,当时有许多文章是研究比特币的PoW(工作量证明)协议的,很少有研究比特币的P2P网络的。比特币的P2P区块链网络被设计成一种开放的、去中心化的独立于PKI的模式。这样,节点间的身份验证无需使用任何密码学机制,IP地址就代表一个节点的身份。
比特币的客户端会主动随机选择8个区块链网络中的节点与其发生连接,这些连接都是长期的连接。同时客户端还可以最多接收任意IP发过来的117个连接请求。节点间就是通过这些连接进行信息的交换的。
日蚀攻击
比特币网络的这种开放性,导致攻击者可以很容易对区块链网络中的节点进行攻击。在日蚀攻击中,攻击者会垄断一个节点发出以及接入的所有连接,从而将该节点与网络中其它的节点隔离开来。在区块链网络中,攻击者可以利用这种方式,向受害者节点发送任意信息以达到攻击的目的。
比特币的P2P网络
想要阻断区块链网络中的节点与外界的连接,必须了解比特币网络对外的连接方式。下面我们简单介绍下比特币P2P网络是如何进行网络连接的。文中描述的比特币区块链网络基于bitcoind客户端的0.9.3版本。
比特币网络中的节点使用IP地址作为他们的身份标识的。一个拥有公网IP地址的节点最多可以对外发出8个连接,接收117个连接。私有IP地址的主机只能发出8个对外的连接。网络中的连接是基于TCP协议的。比特币的网络节点通过比较VERSION消息和IP报文头来判断一个节点是否具有公网IP。下面我们介绍比特币网络是如何中继信息、如何存储网络信息以及如何选择请求连接的节点的。
如何中继网络信息
比特币网络的信息通过两种方式传播:
- DNS种子信息
- ADDR消息请求
DNS种子
比特币客户端节点在首次接入区块链网络的时候会发送一个DNS请求到DNS服务器请求现网的区块链节点的地址信息。如果失败了,则会去连接客户端内嵌的600个IP地址。另外在比特币客户端重启并尝试连接新的对端节点的时候,也有可能发送DNS请求到DNS种子服务器,发送请求的条件是以下两个:
- 节点尝试对外建立连接已经超过了11秒
- 节点少于2个对外连接
ADDR消息请求
一旦比特币客户端与一个节点建立了连接,那么其就可以发送一个ADDR请求消息给对端用于请求对端所知道的网络节点信息。节点最多会响应三条ADDR消息,并且每条消息最多可以返回1000条节点的信息(IP地址和时间戳)。
节点有两种方法将其IP地址信息发送出去:
- 每天节点都会给与其连接的每个节点发送一个ADDR消息,用于报告其IP地址
- 节点在收到ADDR消息后,如果发现其中记录的条数不超过10条,那么它会随机选择两个与其连接的节点,将这条ADDR消息发送给它们
网络信息的存储
节点使用两个表用于存储IP地址信息: tried表和new表。
tried表
tried表包含64个桶用于存储IP地址,每个桶可以最多存储64个IP地址。这些IP地址都是与节点建立过连接的(输入连接或输出连接)。对于每个IP地址,都有一个对应的最近连接的时间戳。每个IP地址都可以映射到一个桶中,桶的下表通过下面的算法生成:
def bucket_index(SK, IP, GROUP):
i = Hash(SK, IP) % 4
bucket = Hash(SK, GROUP, i) % 64
return bucket
其中,$SK$为一个随机值,$IP$为IP地址,$GROUP$为IP地址的16位前缀。由上面的算法我们可以看出,每个IP地址会映射到唯一一个桶中,每个GROUP最多可以映射到4个桶中。
节点每建立一个新的连接的时候,会将对端的IP地址插入到桶中。如果桶满了,那么会随机从桶中挑出4个IP地址,并将其中时间戳最早的那个IP:
- 替换为当前连接节点的IP地址
- 插入到new表中
如果这个IP已经在桶中,那么更新时间戳。在连接的节点发送VERSION / ADDR / INVENTORY / GETDATA消息时,会更新IP地址对应的时间戳(最小更新间隔为20分钟)。
new表
new表中包含256个桶,每个桶也可以存储64个地址。new表中存储的是尚未成功建立过连接的IP地址,主要由两部分组成:1) 从DNS请求获取的 2) 通过ADDR消息请求获取的。一个IP地址插入到那个桶中由两个因素决定:1) GROUP 2) SOURCE GROUP。$GROUP$的定义和tried表中一样,SOURCE GROUP值的是该IP地址是谁发送过来的。计算桶索引的算法如下:
def bucket_index(SK, GROUP, SRC_GROUP):
i = Hash(SK, SRC_GROUP, GROUP) % 32
bucket = Hash(SK, SRC_GROUP, i) % 256
return bucket
由上面的算法可以看出,一个GROUP最多可以存储32个IP地址。每一个桶中存储的地址都是不同的,如果一个桶满了,那么会检测桶中的IP地址:1) 是否超过了30天;2)是否超过了最大尝试连接次数,如果满足其中一条,那么用新的IP地址将其替换。否则,新IP被释放。
连接节点的选择
节点会在启动/重启或者在发出的连接被对端关闭的时候,重新对外发起一个连接请求。选择连接节点包含两个步骤:1) 选择一个表 (tried/new)2) 选择一个IP地址
选择表
比特币客户端使用一个随机概率模型选择使用哪一个表。在选择第$\omega \in [0, 7]$个连接节点时,tried表被选中的概率为:
其中
简单来看,$\omega$越大,从tried表中选择节点的概率就越小。下图给出了不同$\rho$时,tried表被选中的概率。
选择IP
IP选择也是个概率模型,分三步:
- 随机选择一个桶
- 随机选择桶中的一个IP
- 这个IP被选中的概率由下面概率决定
$r$为到当前为止,已经拒绝IP的次数;$\tau$为$\frac{当前时间 - IP时间戳}{ 10分钟}$,也就是IP保存了多少个10分钟没有更新了。显然越新被选中的概率越大。如果IP没有被选中,重新进入第一步。
攻击详解
攻击方法
攻击主要分为以下几个步骤:
- 用攻击者控制的IP填满tried表
- 用无用IP填满new表
- 不停攻击,直到受害者客户端重启
- 重新建立连接时,受害者所发出的连接只能从tried表中选择对端,这样就只和攻击者建立了连接
- 占据受害者的接入连接,这一步很容易实现,攻击者可以一直向受害者发出连接
tried/new 表IP植入
由于tried表会在建立新的连接时被更新,因此,需要植入该表只需要攻击者使用所控制的IP节点向受害者节点发送连接请求即可。根据替换规则,受害者客户端会选择时间戳较久的来替换,因此这个表很快就可以被攻击者IP填满。
由于客户端会将$ADDR$消息中的IP地址直接插入到new表中,而且并不会去检查这些IP是否有效,因此要填满new表只需要向受害者节点建立连接并且发送$ADDR$消息即可。$ADDR$消息中最多可以包含1000条IP,攻击者可以在这里面填写一些无法建立连接节点的IP。
等待受害者客户端重启
在很多情况下,攻击者的客户端会重启,比如:更新、系统出错等等,一旦客户端重启攻击就成功了。也有一些方法可以让客户端被迫重启,比如DDoS攻击等。
理论分析结果
这里我们简单给出一些理论分析的结果,如下图所示:
其中横坐标为$f=tried表中攻击者IP所占比例$,纵坐标为攻击成功概率,我们可以看到在攻击48小时的情况下,即使$f=0.72$,攻击也有90%的成功率。
图中的虚线表示作者实验中修改了IP替换策略:将使用较旧的IP替换改为随机选择一个IP替换。可以看到,这时候攻击成功的概率会下降。要在48小时内达到攻击成功率90%,需要填满98.5%的受害者tried表。
攻击资源需求分析
文中分析了两种攻击方式,其中一种为使用肉鸡(Botnets)进行攻击,下面我们给出在攻击者控制了$t$个肉鸡的情况下,可以占据tried表中IP地址位置的数量的图表:
从上图可以看出:表为空时,肉鸡数量需求较少。如果表不是空,那么填满tried表中同等数量的IP位置,那么采用比特币客户端的IP替换方案时(绿色线)比采用随机替换方案(橙色线)需要更少的肉鸡。显然比特币的替换方案更容易遭到攻击。
以现网肉鸡的规模来看,很容易达到攻击要求。
试验测量
文中搭建了攻击环境,对于该攻击进行了测量,结果如下。
其中Infra表示那些拥有很多IP资源的机构如果想要攻击的情况,上文我们没有叙述,主要这种攻击不如肉鸡攻击简单,而是成功率也没有使用肉鸡攻击高。这里我们主要看下使用肉鸡攻击的结果。
表中各列含义为::
- grps 表示IP地址中包含GROUP(IP地址16位前缀)的数量
- addrs/grp每个GROUP包含IP地址数量
- total addrs总IP地址数量
- $\tau_t$攻击时间
- $\tau_a$每一轮攻击时间(每一轮都需要受害者客户端重启一下)
- Total pre-attack攻击前表中IP地址数量
- Total post-attack攻击后表中IP地址数量
- Attack addrs攻击后攻击者IP地址在表中的数量
- Wins攻击成功概率
各行含义:
- Worstcase: 最差情况
- Transplant:这个实验环境是作者将实际运行的比特币节点移植到不同IP的服务器上进行的
- Live:作者搭建的线上的比特币节点
结果的主要发现
在worstcase中,攻击者所的IP需求量较大,但是在此情况下,攻击成功率达到了100%。
实际攻击的成功率比预测的要高。这是由于,在前文的理论分析中,作者对于成功攻击限制较大:分析时,作者假设new表中所有IP都需要被攻击者用无用IP填满,实际攻击时并不需要这样。
在现网的测试中,作者只使用了400个肉鸡节点就达到了84%的攻击成功率。
解决方案
- 节点驱逐方案修改:在桶满的时候,对于替换策略进行修改:原先为从一个桶中随机选择4个,而后将最旧的替换;改为,将IP地址也采用和桶一样的固定映射策略(使用哈希计算其在桶中的索引)。这样攻击者就不能反复使用同一个IP进行填充(因为其被映射到了同一位置)
- 节点选取方案选择:之前在节点选取时,节点倾向于选择较新的节点来进行连接,这样容易被攻击者利用;改为随机选取连接节点
- 驱逐前测试:在选择替换一个IP地址时,先测试一下,这个节点能否被连接,如果可以就不进行替换,即使其时间戳较旧。这就极大加强了攻击者的IP注入的难度
- 连接感知:随机选择new表中的一些IP地址建立短的连接,如果成功,将地址加入到tried表中
- 锚连接:建立一个锚连接表,用户记录节点对外发出的成功连接。每次重启的时候,从这个表中选择两个IP进行连接。这样攻击者,必须首先攻破这个锚连接表才能攻击成功
其它还有一些解决方案也可以帮助防御日蚀攻击,比如:增加桶数量、发出更多的连接、禁止主动输入的$ADDR$地址等等,具体可以参考论文。
结束语
日蚀攻击对于比特币网络的稳定性影响还是比较大的,日蚀攻击可以被用来进行许多其它的攻击,比如双花攻击、算力浪费、使用较少的算力操控比特币网络等等。
本文针对比特币的P2P网络,建立了日蚀攻击的模型,对其进行分析,并且在现网进行了实验分析。实验给出了攻击成功需要的成本,在最后文章还给出了一些解决方案,其中一些已经被集成到区块链网络中去。
引用
[1] Heilman, Ethan, et al. "Eclipse attacks on bitcoin’s peer-to-peer network." 24th {USENIX} Security Symposium ({USENIX} Security 15). 2015.
更多推荐