间谍、毒犯与谣言---比特币与“暗网”的匿名性讨论
在文章《Bitcoin网络中的“黑暗森林”》中我们说比特币网络就是一个“黑暗森林”,转账交易的双方互不“可见”。“暗网”也是如此,你可以访问“暗网”中的服务,但不知道服务器在哪里,服务器也不知道是谁访问了它。那么,它们隐藏通信双方身份的方法是一样的吗,分别是如何做到的呢?在回答这个问题之前,我先举几个生活中的例子。
间谍
前几年谍战片霸占银幕,大家必定对间谍的慎密思维和临危不乱的心理素质印象深刻,更有“双面间谍”让剧情跌宕起伏,引得观众或喜或忧。大家从中也可以知道,所有的间谍都是“单线联系”,也就是说,间谍只与其直接上线或者直接下线联系,而且是“一对一”联系,上线与下线之间互不知道。当一个间谍被捕后,他最多只知道他的上线和下线,不知道“组织”中的其他人,从而最大程度地避免了整个间谍组织被“一锅端”。当“总部”要完成某个谍报任务时,会通过“大Boss”向其直接下线下达命令,直接下线接到任务后再与其直接下线联系,任务层层传达直到“一线”人员。最后收到任务的执行人员并不知道命令最初来自哪个“大BOSS”,“大BOSS”也不知道任务最终由哪个“组织”成员执行(除非他破坏规则,让下线组织上的人层层汇报)。这就是一个典型的通信双方互不知道的例子,其中最重要的机制就是“单线”联系。
毒犯
在TVB警匪片的长期熏陶下,大家必定也对绑匪索要赎金或者毒品买卖双方约定接头和交易过程的情节也耳熟能详了。绑匪索要赎金的大致套路是: 先通知家属准备赎金,并约定拿赎金的地点和时间。然后在约定的地点附近暗中观察,看是否有是真的交赎金的家属还是由警察扮演的,一般狡猾的绑匪在确定交赎金的人后会再次约定一个地方交易,而且为了防止警察找到其藏匿地点,接头的地点一般远离其落脚点。绑匪为了避免被追踪到位置,会选择变换交易地点,然而只要他出来拿赎金,他就暴露了。聪明的绑匪甚至会让家属将赎金放到指定地点,然后找一个陌生人去取。无论如何,绑架大概率会暴露绑匪而且不能持续,尽管如此,绑匪还是要在交易过程中不断变换地点尽可能地避免暴露自己的位置。可以看出,变换交易地点和找陌生人代替自己交易是一个隐藏自己的办法。
相比于绑匪暴力索要赎金而言,毒品交易显得更有“技术性”。毒贩制毒贩毒不是一次性的,他需要设计更周密的交易环节来避免暴露。常见的剧情是这样的: 吸食者联系片区的小混混拿货,小混混从“大哥”处拿货,“大哥”从毒贩子处拿货,毒贩子与制毒团伙交易。吸食者只知道小混混,不可能知道最终的制毒团伙。毒贩子与制毒团伙一开始双方互不相识,需要中间人介绍。也就是说,毒贩子需要“进货”时,会通过“中间人”了解购货的渠道。制毒团伙隐藏在暗处,其他人包括毒贩子也不知道联系他的途径,但他们会保持与信任的“中间人”联系并通过“中间人”介绍客户。买卖双方均通过“中间人”传递买和卖的信息,而不透露自己的位置和身份。“中间人”居中协商好交易量、交易金额和交易时间、地点和方式,同时约定好接头暗号。到时,买卖双方均派出“代表”在约定的时间和地点通过暗号接头,开始交易。交易完成后,买方和卖方均不知道对方的实际身份和藏身位置。一旦吸食者或小混混被抓,警察也无从得知最后的制毒团伙是谁、在哪里藏身;类似地,制毒团伙被警察摧毁后,也不能提供任何关于吸食者的信息。毒贩交易的过程近乎完美地解决了隐藏吸食者与制毒者的问题,其中的关键“技术”手段是: 通过中间人来联络买家和卖家、每次交易约定不同的交易地点、真实的买卖双方均通过“代表”交易。
谣言
间谍和毒犯为了避免暴露,真是煞费苦心,成本也是相当高的,因为它们均依赖于一个严密的组织。那么到底有没有低成本的方案来让通信或者交易的双方不暴露呢?有,那就是造谣。如果希望消息传递出去,又不希望其他人知道消息的来源和目的地,可以通过散布谣言的方式。将消息“隐藏”在谣言中并散布出去,谣言散布的地域越广,被越多的人传播,查到谣言源头的难度就越大;同时,谣言并不指定具体的接收者,感兴趣的人接收到后会自行解读,但其他人并不能知道被谁解读了,从而达到了隐藏消息源和接收者的目的。
看到这里,大家是否隐隐觉得上述三种场景所采用的“隐藏”手段与我们将要讨论的比特币和“暗网”中的技术有关联呢?实际上,我们常常听到的比特币可以隐藏转账双方的身份信息的特点就是采用类于谣言的方式实现的,“暗网”中提供的隐藏服务(hidden service)就是采用类于于间谍的单线联系和毒犯在交易中的各种“保护”手段来实现匿名的。
为了说明匿名性,我们首先简要说一下网络上如何被“跟踪”。我们举常见的网页访问的例子。当我们从自己的电脑上通过浏览器上网访问一个网址时,我们的电脑与网站服务器之间会建立一条TCP连接,这条连接通过源IP和端口号、目的IP和端口号来唯一标识。这条连接上的数据会被封装成IP数据包,经过网络运营商的路由器转发。网络运营商的路由器可以“截获”这条连接上的IP数据包,即使我们对这条连接上的数据进行加密,运营商仍然可以知道它的源IP和目的IP,从而确定通信双方的位置。生活中,我们可能通过代理上网,那么这条连接的源IP就是代理服务器的出口IP,运营商可以通过它定位到代理服务器,由于我们的电脑与代理服务器也有一条TCP连接,运营商可以进一步定位到我们的电脑的IP。也就是说,即使我们均通过加密通道(TLS)上网,我们的所有数据均可以通IP地址被跟踪到。那么如何做到反“跟踪”呢?可以在我们的电脑与网站服务器之间建立多条而不是一条TCP连接。通过代理上网就是建立了两条TCP连接,一条是我们的电脑与代理服务器之间的,另一条是代理服务器与网站服务器之间的,运营商联合分析这两条连接的源IP和目的IP就能知道我们电脑的IP和网站服务器的IP。然而,当我们的电脑与网站服务器之间建立多个TCP连接,即建立多级代理时,运营商必须同时跟踪到多条连接才能准确分析出源IP和目的IP,这个难度将大大增加,因为它必须找出所有以某个代理服务器IP为源或者目的的连接,再分析这些连接的目的IP和源IP,找到下一级和上一级代理服务器,再递归分析上一级和下一级代理服务器相关的连接,逐级收集和分析所有连接才能最终确定我们的电脑的IP和网络服务器的IP。特别地,如果我们的电脑与网站服务器之间的代理服务器是动态变化的,甚至是跨运营商或者跨国家的,那运营商追踪源和目的将变得异常困难。请注意,我们这里均假设TCP连接上的数据已经加密,即通过TLS通信;如果数据未加密,运营商通过分析应用层协议将更容易追踪连接的源和目的。代理服务器实现了“单线联系”,即从TCP连接来看,代理服务器的上一级与下一级互不知道,但是如果TCP消息内容(即应用层协议数据)未加密,有些代理服务器会修改消息内容,将途径的中间代理服务器的IP添加到消息内,从而打破“单线”联系的规则,使得源和目的变得容易追踪。总之,网络通信的双方的IP地址和端口号是能被中间节点“看到”并分析出其位置的;但通过多级动态代理,可以实现反“跟踪”。
比特币的匿名性
我们知道,比特币网络是一个P2P网络,即节点与节点之间通过TCP连接成为Peer。当其中一个节点上产生一笔交易(Transaction)A时,它会将该交易广播给它的Peer,Peer收到后又会向它的Peer广播,即交易A在全网flooding。矿工在收到交易A后会试图将其打包到一个新的区块中并开始“挖矿”。某个矿工成功“出块”后,也会将包含该交易的区块向其Peer广播,并进一步向全网flooding。一段时间后,如果另一个节点上产生了一笔交易B,且其输入是交易A,它并不关心交易A是在哪个产生的。其过程如下图所示:
图中蓝色节点表示交易产生的节点,黑色节点表示矿工节点,红色表示引用交易的节点;黑色线段示意交易传播路径,橙色线段示意区块传播路径。
可以看出,交易或者区块的传播并没有指明目的地,也不会携带源的信息,它们在P2P网络中“任意”传播,对它们感兴趣的节点接收到后自己处理,这就类似一个“谣言”传播的过程。需要注意的是,比特币网络在传播区块或者交易时,并没有采用TLS加密通道,在TCP连接上的数据是可以被“窥视”的,然而协议消息里并不含任何源IP、目的IP或途经节点IP的信息,所以中间节点不能通过解析比特币协议消息来获取源或目的的消息。消息在P2P网络上传播时,任何节点都可以看作是一个代理,天然实现了多级代理,所以通过TCP连接的IP地址去追踪交易或者区块的源头也是相当困难的。需要注意的是,比特币地址与IP地址没有任何对应关系,而且比特币账户可以通过任何一个节点交易,所以知道比特币地址是无法定位交易者的身份和位置信息的。
比特币节点之间无需建立加密通道,只需要维护Peer连接,当网络规模越大时,越难追踪交易的源和目的位置,因为采用了类似“谣言”的方式实现匿名性,它较“暗网”的匿名性实现要简单许多。
“暗网”的匿名性
“暗网”是由Tor(The onion router,洋葱路由器)组成的网络。Tor是由分布在全球的志愿者在自己的连网设备上运行Tor程序实现的,所以“暗网”是不受控于网络运营商的自由组织。“暗网”是一个多级中继网络,在通信通道建立时,会选择不同的Tor在源和目的之间建立“虚电路”,实现多级代理,建立“虚电路”的各个Tor之间采用TLS加密通道通信。更重要的是,为了防止中继Tor“窥探”消息内容,源Tor会将待发送的消息经过多层加密后放入TLS通道传递出去。由于对消息进行了多层的加密以及“虚电路”各段之间采用TLS加密通道,密钥的协商和消息的加密过程会导致建立连接的过程相对“缓慢”,所以源Tor和目的Tor之间的数据会共享“虚电路”,然而为了避免通过“流量”分析数据的流向,源Tor和目的Tor之间的“虚电路”会10分钟更新一次路径,随机选择不同的Tor再建立一条。Tor的“虚电路”实际上建立在TCP连接上,为了避免不同的应用数据在同一个TCP连接上传输,Tor支持“Stream Isolation”,允许不同数据在不同的TCP连接上传输,正如我们在《Btcd区块在P2P网络上的传播之ConnMgr》中介绍的那样。
“暗网”可以提供两类服务,一类是提供代理服务用于隐藏用户信息,如我们可以通过Tor代理或者Tor浏览器访问一个“明网”中的网址(如www.google.com),这样网络中的其他节点,包括网站服务器,均不知道是谁访问了google;另一类是提供hidden service,用于隐藏服务(比如网站)的位置,如可以在暗网中部署一个web服务器,其他人就可以通过洋葱地址(如xxx...xxx.onion)访问该web服务,但网络中的其他节点不知道这个web服务器的具体位置。我们将分别介绍这两类服务是如何实现的。
下图是通过Tor代理访问“明网”中服务的过程:
图中Alice表示用户,Blob表示网络服务提供者或者Alice的通信目标。绿色节点代表Tor,其中进入Tor网络的第一个Tor称为Guard Node,离开Tor网络的最后一个Tor称为Eixt Node,中间的Tor统称为Middle Node,三段TLS连接构成Tor代理到退出节点之间的“虚电路”。黑色节点代表普通路由器,即非Tor路由器。Tor之间的粉色、橙色和蓝色线段表示TLS连接。Alice通过Tor代理上网的过程如下:
- Alice与洋葱代理服务器建立TCP连接,通过SOCKS协议申请建立代理连接;
- 洋葱代理查询内置的Tor网络的Directory Server,获取Tor网络中所有活跃的Tor信息;
- 洋葱代理从活跃的Tor中随机挑选三个以上的Tor,开始构建“虚电路”,如图中的 2, 3, 4 所示,具体的构建过程将在本文后面介绍;
- 退出节点建立与Blob的TCP连接,如图中 5 所示;
- Alice开始与Blob通信;
Hidden Service的实现过程稍微复杂一些,其过程如下图所示:
建设好Web站点(Blob),在发布之前,要为它分配一个洋葱地址,这个地址与比特币地址类似,是Blob的公钥经过字符编码成16个字符,并添加.onion后缀形成的。我们省略了Alice和Blob与Onion Proxy建立连接的过程,Blob发布服务及Alice访问Blob的过程如下(以下对Blob或Alice的表述均指它们的Onion代理):
- Blob访问内置的Directory Server,获取活跃的Tor列表;
- Blob从活跃的Tor中选择若干节点作为Introduction Points,随后将服务的摘要、洋葱地址、IR等信息签名后,写入Tor的lookup service;
- Blob与自己选取的各个IR建立“虚电路”连接,并告诉它们自己等待其他人访问;
- Alice如果要访问Blob,她首先访问内置的Directory Server,获取活跃的Tor列表;
- Alice通过lookup service查询到Blob的IR列表,并选择其中一个与之建立“虚电路”连接;
- Alice从活跃的Tor中选择Rendezvous Points,并将自己的临时Cookie和RP发送给IR,由IR转发给Blob;
- 随后,Alice与RP建立“虚电路”连接,Blob知道Alice选择的RP后,也与RP建立“虚电路”连接,并发回Alice的临时Cookie,由RP将Alice的连接与Blob的连接关联起来实现Alice与Blob的互通;
这里可以作有意思的类比,IR相当于中间人,RP相当于交易地点或者经手人,Cookie相当于接头暗号,也就是双方通过中间人取得联系并协商交易地点和接头暗号,然后在约定的交易地点接口,其过程与毒贩交易过程如出一辙。特别地,Alice或者Blob与IR或RP之间的连接均是通过“虚电路”连接,“虚电路”实现了多级代理和多层消息加密,而且代理之间的消息在TLS上传输,保证了除Exit Node以外的其他Tor无法解析或者跟踪消息内容或传输路径。我们借用torproject上的tor设计spec来介绍“虚电路”的建立过程:
图中的Alice是指Alice的Onin代理,为了简化说明,图中只列出了两个中继Tor,OR 1既作Guard Node也作Middle Node,OR 2作Exit Node。可以看到Alice与OR 1以及OR 1与OR 2之间均采用TLS连接。需要注意的是,所有Tor上均有两对密钥对,其中一对用于建立TLS连接;另一对用于DH密钥协商,如图中的E(x)所示。下面我们逐步解释上述过程:
- 图中1和2步完成Alice与OR 1之间的密钥协商。其中第1步,Alice向OR 1发送Create circuit的请求,并将用于DH协商的素数p,生成函数g,以及E(g^x1)发送给OR 1,其中x为Alice生成的安全随机数,E(g^x1)表示用OR 1的公钥对g^x1进行加密;
- 在第2步中,OR 1收到Alice的Create circuit请求后,用其私钥解密出g^x1,并随机生成y,通过K1=(g^x1)(g^y1) mod p计算出密钥K后,将g^y1和Hash(K1)回复给Alice;Alice收到OR 1回复的g^y后,也通过K1=(g^x1)(g^y1) mod p计算出密钥K1,同时计算出Hash(K1)与OR 1发送过来的Hash(K1)比较,以确认g^y1确实是OR 1(收到g^x1的节点)发送过来的;
- Alice与OR 1协商出密钥K1后,它们之间的circuit就建立完成了。随后,Alice通过OR 1与OR 2协商她与OR 2之间的密钥K2。在第3步中,Alice向OR 1发送Relay命令,携带用K1加密后的Extend消息,指明要求OR 1与OR 2创建circuit,同时用OR 2的公钥加密g^x2一同发给OR 1;
- 在第4步中,OR 1收到Alice的加密消息后,用K1解密,发现是Extend到OR 2的消息,于是向OR 2发送Create命令,并将E(g^x2)发送给OR 2,请注意,这里的g^x2是通过OR 2的公钥加密的,OR 1是无法知道其值的;
- 第5步类似于第2步,OR 2将通过K2=(g^x2)(g^y2) mod p计算出密钥K2;OR 2将g^y2和Hash(K2)发送给OR 1,由于OR 1并不知道g^x2,它无法算出K2;
- 第6步中,OR 1将收到的OR 2的信息通过K1加密后回复给Alice,这样Alice就与OR 2协商出了K2;到此,Alice经过OR1与OR2之间的“虚电路”就建立了,如果有多个Tor,就重复3,4,5,6的过程逐级协商密码并建立circuit,直到退出节点;
- "虚电路"建立完成后,Alice就可以通过其访问website,她先发送Begin消息给OR 2,如果图中步骤7,8所示。请注意,Begin消息在Alice经过了两道加密,先用K2加密,然后对加密结果用K1进行二次加密;OR 1收到该消息后,用K1解密,得到的结果仍是加密数据,所以OR 1并不知道要访问的目标网址; 随后,OR 1将K1解密后的数据发往OR 2;
- OR 2收到加密消息后,用K2解密,得到Begin消息,然后开始建立OR 2到website之间的TCP连接。
- 退出节点OR 2与websit的连接建立后,OR 2将结果用K2加密回给OR 2,如果步骤9所示;
- OR 1将收到的消息用K1再次加密后回复给Alice,如果步骤10所示。Alice收到OR 1的加密消息后,先用K1解密,再加K2解密,可以得到OR 2回复的消息。
可以看出,Tor网络中Guard Node与Exit Node之间建立了一条完全“保密”通道,它们之间的中间节点无法获知通信的任何信息,包括消息的上上级来源、下下级目的地及消息内容。发送消息时,Guard Node会对消息内容用协商好的密钥集层层加密,在Middle Node中转发时,消息被逐层解密,直到Exit Node才能得到明文消息。层层加密使得用户消息被“包裹”在最内层,像一个“洋葱”一样,这也是“洋葱”网络名字的由来。在上述例子中,我们可以看出,website只知道OR 2访问了它,而不知道是Alice,从OR 2开始后续的所有节点均不知道Alice的任何信息,这样就无法追踪到“源”;同时,除了Alice自己和退出节点OR 2,其他节点均不知道请求的目的地是website,这样就无法跟踪到“目的地”;中间节点将完全不知道它转发的是什么。
“暗网”中通过中继Tor建立的“虚电路”实现了多级代理,一方面达到的“单线”联系的目的,另一方面也防止了“代理人”窃取消息内容;同时,它通过Introduction Points和Rendezvous Points等类似于“中间人”和“接头地点”等方式保护了服务的位置,从而实现了对用户和服务的隐藏,提供了很好的匿名性。当然,它的代价也是高昂的,它需要多次协商密钥和加、解密,同时由于Tor是志愿者自建的,一定程序上会受到贡献者的带宽限制。比特币则采取了更简单的类似“谣言”在全网通过“不明真相的群众无脑转发”的方法,用较低成本实现了其匿名性。