TOR原生数据填充方式(Channel Padding)

TOR本身已经做了这个功能了,今天发现。TOR 0.3.1.7版本加入的流量分析阻力,ChannelPadding,2017年9月

颇为绝望。今天才在GITHUB上看见TOR padding specification。

然后赶紧找了找官方的版本更新说明 原文如下:

Major features (traffic analysis resistance):

  • Connections between clients and relays now send a padding cell in each direction every 1.5 to 9.5 seconds (tunable via consensus parameters). This padding will not resist specialized eavesdroppers, but it should be enough to make many ISPs’ routine network flow logging less useful in traffic analysis against Tor users.

    Padding is negotiated using Tor’s link protocol, so both relays and clients must upgrade for this to take effect. Clients may still send padding despite the relay’s version by setting ConnectionPadding 1 in torrc, and may disable padding by setting ConnectionPadding 0 in torrc. Padding may be minimized for mobile users with the torrc option ReducedConnectionPadding. Implements Proposal 251 and Section 2 of Proposal 254; closes ticket 16861.

  • Relays will publish 24 hour totals of padding and non-padding cell counts to their extra-info descriptors, unless PaddingStatistics 0 is set in torrc. These 24 hour totals are also rounded to multiples of 10000.

原文地址:点击打开链接

总的大体意思是 在中继和客户端间每1.5到9.6秒发送一个填充数据元在所有方向上(可通过一致性参数调整),填充不针对专门的窃听者,但能够破坏ISP常规网络流记录对TOR用户的流量分析。填充使用TOR链接协议,因此中继和客户端必须进行升级才可使用。客户端仍然可以发送填充,只要中继版本里的torrc设置了连接填充为1,并可通过设置为0来禁用。当移动用户设置了ReducedConnectionPadding 在torrc里时,填充会在最小的方式进行。中继会24小时发送填充数据元和非填充数据元(基于他们额外信息描述符),除非torrc设置了PaddingStatistics 为0。

好吧,大体意思是这样,那我们再来看看,具体是什么情况。来尝试看看TOR的Specification是怎么描述这个功能的。

Github上的TOR-SPEC

1.1 概览

TOR支持两种级别的覆盖流量,连接级别填充和链路级别填充。

连接级别的填充使用 CELL_PADDING数据元命令用来填充流量,而链路级别填充使用RELAY_COMMAND_DROP中继命令。CELL_PADDING是单跳的,且可被中继将之与正常流量区分开(内部检查器),而无法被外部区分(外部观察者)

RELAY_COMMAND_DROP是多跳的,并且对途经的中继不可见,因为中继命令域已被(circuit)链路层加密。并且,TOR的”可识别“域允许RELAY_COMMAND_DROP填充流量发送至该链路中的任意中间节点。

如今只有单跳的CELL_PADDING被使用(其实我看了一下0.3.1.7,貌似多跳的RELAY_COMMAND_DROP也被使用了)

连接级别的填充:

2.1背景:

TOR客户端和中继使用CELL_PADDING来对抗IPS和其他的监察者对连接级别的元数据搜集。这些流数据采集检测在互联网路由器中以NetFlow,JFlow,NetStream或IPFIX记录的形式实现。(这些都是各大路由厂商比如华为、思科等设备的数据流形式)。这些记录被网关路由以原生形式获取,并输出给(一般都是明文形式)一个既不逐字记录也不减少其记录粒度的采集器(我的理解是一个比较完整地记录的采集器。)

网络流记录和其相关的数据搜集工具都是可配置的,且有许多操作模式,特别是当其配置于解决高数据量通过时。然而,在ISP维度,每一种流的记录都很可能被使用,因为他们既是默认的也提供了一种对终端活动的高可分辨性。其次仅对全包或者包头进行捕获。

单流记录以五元组的形式记录一个终端的连接,包括一段特定时间内总计发送接收的字节数。他们也可以存储额外的域信息,但我们关注的一般都是时间信息及字节计数信息。

当配置于提供单流记录时,路由器周期性发送所有通过他们的连接的原生流记录,基于两个参数“active flow timeout”,”inactive flow time out”。

“active flow timeout”使路由器周期地发送一个关于所有持续发送数据的活动的TCP会话的新的记录。大多数路由器默认的活动流超时时间使三十分钟。意味着一个新纪录至少会每三十分钟产生一次,不管如何,这些值可以配置成1分钟到六十分钟,在主流路由器上。

“inactive flow timeout”使路由器在一个TCP会话超时一定时间时产生一个新的记录。允许路由器避免追溯内存里一大堆的终结连接和在有活动的时候发送一个单独的记录。在通用路由器里这个值域一般是10秒到600秒,目前似乎没有路由器支持小于十秒的该值。

罗列一些主流路由的两个参数列表

                        路由                                      Activeflow time out                  Inactiveflow time out

  Cisco IOS[3] 15s (10-600s) 30min (1-60min)
  Cisco Catalyst[4] 5min 32min
  Juniper (jFlow)[5] 15s (10-600s) 30min (1-60min)
  Juniper (Netflow)[6,7] 60s (10-600s) 30min (1-30min)
  H3C (Netstream)[8] 60s (60-600s) 30min (1-60min)
  Fortinet[9] 15s 30min
  MicroTik[10] 15s 30min
  nProbe[14] 30s 120s
  Alcatel-Lucent[2] 15s (10-600s) 30min (1-600min)

这张表允许我们设计一个低代价的填充对抗方式,使路由产生的记录在他们输出到采集器进行存储前崩塌(就区别于实际的流量记录)。在一个连接在不活动流超时前传输数据时,路由器会继续对数据流进行计数直到活动流超时。

这意味着对于阻止不活动流超时的最小填充数,这是有可能减少在大小为30分钟的窗口内原生数据收发数据总量可分辨性的,

对于HTTP,IRC,XMPP,SSH和其他断断续续的内在互相关联的流量,特别是所有用户流量在一定时间内都从一个连接上通过时,这种方法能够大量减少这些流量记录的可变性。(TOR便是在连接上复用多个通道,通道上复用多个链路)

实现

Tor客户端当前保持一个TLS连接到他们的入口节点来承载实际的应用流量,并且额外建立三个连接到其他节点来获取目录信息。我们仅仅对客户端到入口节点的连接进行填充,而忽略任何其它的连接。我们把对网桥节点到Tor网络的连接看作客户端连接,也填充他们,但其他正常中继间不进行填充。

客户端和入口节点都会对所有应用TLS连接维持一个计时器,每次一个非填充包被对端接收或发送时,终端将会通过max(x,x)分发方式(稍后会提到)从1.5s到9.5s之间抽取一个超时值。这个时间范围取决于一致性参数(稍后也会提到)。

如果连接在计时器超时前开始活动了,计时器会重置为1.5s到9.5s间一个新的随机值,如果连接保持不活动直到计时器超时,一个单独的CELL_PADDING包将被发送到该连接上。

通过这种方式,连接填充只会发生在空闲阶段,并且最小十秒的非活动超时时总会传输一个数据报。

填充数据元超时分配计数

由于填充时双向的,并且双端都会维持计时器,因此该时间在向双端发送填充包前都是min(client_timeou,server_timeout)。

如果client_timeout和server_timeout都是一致地抽样,则min(client_timeout,server_timeout)将不再一致地分配且平均的超时结果(Exp[min(X,X)])会较范围中值低。

为了弥补此不足,相对于平均地从每个终端一致地抽样超时,TOR会使用max(X,X)进行抽样,X为一致分配的

如果X是一个一致随机变量,范围为0到R-1(R=high-low),则随机变量Y=max(X,X)有(Y==i)=(2.0*i+1)/(R*R)

当双端均从Y中产生超时值,则双向填充数据包发送率为第三个随机变量Z=min(Y,Y).

Z的分布是略显钟罩形的(参见正态分布曲线),但集中于中值,也显示Exp[Z]~=Exp[X],以下为每个变量的均值表

R Exp[X]    Exp[Z] Exp[min(X,X)] Exp[Y=max(X,X)]
2000 999.5 1066 666.2 1332.8
3000 1499.5 1599.5 999.5 1999.5
5000 2499.5 2666 1666.5 3332.8
6000 2999.5 3199.5 1999.5 3999.5
7000 3499.5 3732.8 2332.8 4666.2
8000 3999.5 4266,2 2666.2 5332.8
10000 4999.5 5328 3332.8 6666.2

通过这种方式,我们保证了超时范围的中点是填充数据报双向发送期望的均值时间

最大值上界

通过使用默认参数和以上分配的方式,我们期望一个被填充的连接会每5.5s发送一个填充数据元。平均一秒会有103个字节被完全发送(即单向会发送52个字节每秒),假设一个512字节的数据元和55字节的TLS+TCP+IP头部。

对于一个客户端连接,当其保持空闲时其期望一个50分钟的生存期(基于链路空闲超时加上一个较小的额外连接超时),这大约有154.5kb上界在每个方向上(总计308KB)

每天有将近250万的日常用户在使用TOR网络,52B/s,在整个TOR网络范围内即130MB/s(在每个方向上),即当前TOR目录流量的大小。但250万的日常用户不会都同时连接,也不会都一直完全空闲,因此我们估计实际的耗费会比这更小。

通过协商减少或禁用填充

为了允许移动客户端可以减少或者禁用他们的填充开支,客户端可以发送CELL_PADDING_NEGOTIATE到中继。这个数据元用来告诉中继减缓发送填充数据元。

若客户端选择了填充减少,它会持续发送填充数据元,但时间间隔为[9000,14000]ms的范围中抽样(取决于一致性参数,后面会提到),仍然使用Y=max(X,X)分配方式。填充是单向的 ,则预计的填充规律取决于Y而不是Z,对于5000ms范围内的取值,我们可预计在9000+3332.8=12332.8(也就是12秒)的时间内发送一次填充包。我们将链路可用超时减半(50min减为25min),这会导致客户端的OR连接会在其空闲后很快关闭,以减少耗费。

这两个变化导致了每次用TOR连接的填充耗费从309kb减到了69kb,对于连续的使用,最大的耗费从103kb/s减少到了46kb/s

如果客户端选择了完全禁用填充,它会发送一个CELL_PADDING_NEGOTIATE 包来告诉中继不要进行填充,接下来它将不会发送任何填充数据包。

实现行为控制的一致性参数

连接层次的填充是被以下一致性参数控制的。

*nf_ito_low (netflow inactive timeout low)

    不活动填充时间范围下界,当不活动时 默认值:1500 ms

*nf_ito_high(netflow inactive timeout high)

    不活动填充时间范围上界,默认值:9500ms 若nf_ito_low==nf_ito_high==0 即填充被禁用

*nf_ito_low_reduced(reduced netflow inactive timeout low)

    客户端设置减少填充时的不活动填充时间范围下界 默认值:9000ms

*nf_ito_high_reduced(reduced netflow inactive timeout high)

    客户端设置减少填充时的不活动填充范围上界 默认值:14000ms

*nf_conntimeout_client(netflow client connection timeout)

    保持链路打开且可为用户所用的时长,实际用户超时时间是这个值到其二倍值范围内的完全随机数。这确定了客户端OR连接的生存周期,选择减少填充的用户使用该一致值的一半 默认值:1800s

*nf_pad_before_usage

    若设置为1,OR连接会在用户开始将其用于任何应用流量前进行填充,若设置为0,则OR连接会直到应用流量开始发送时才进行填充,默认值:1

*nf_pad_relays

    若设置为1,不活动的OR-OR连接也会被填充,默认值:0

*nf_conntimeout_relays

    空闲的OR-OR连接保持开启的时间 默认值:3600s