徐婉冰 王軼駿 薛 質 姜開達
(上海交通大學網絡空間安全學院 上海 200240)
隨著計算機網絡的快速發展,暗網的規模也快速增大。暗網在廣義上指無法被搜索引擎收錄內容的站點,目前最流行的訪問暗網的方法是Tor[1]。Tor是一種暗網協議,通過在Tor網絡的入口和出口節點間隨機選擇若干匿名中繼節點建立加密鏈路,實現類似洋蔥的逐層加密網絡。
由于Tor具有雙向匿蹤特性,即消息的發送者和接收者無法知道彼此的IP地址,它可被用于抵御網絡監控、分享私密信息、瀏覽被禁網站等,因此一些國家或企業會禁用Tor,最直接的方法是封鎖Tor目錄服務器和所有已知節點的IP。為了應對IP封鎖,誕生了Tor bridge(網橋)[2],它本質是Tor的入口節點,部署在不受監控的區域。由于官方不會公開完整的bridge列表,所以ISP無法徹底封鎖bridge。
然而審查者仍可以基于TLS handshake的指紋特征檢測Tor流量及其他可疑流量[3]。對此,研究者們提出了Pluggable Transports(PT),一種用于隱藏Tor流量的網橋工具。PT連接Tor客戶端和Tor網橋,通過混淆和偽裝等手段,使Tor流量看上去是普通的協議,從而躲避檢測。
當前,國外對于PT流量檢測的研究主要從熵檢測、語義分析和機器學習三方面開展,檢測的目標以Tor官網建議的Meek[5-7]、Obfs系列、FTE系列為主,在理想環境下都能以較高準確率進行識別。相比檢測,近年來幾乎沒有新的流量隱蔽方案。同時,國內對Tor流量隱蔽問題[4]整體缺乏研究。本文主要貢獻如下:
(1) 研究了已有的PT方案,分析了常見檢測方法的優缺點;
(2) 不同于以往僅對通信內容加以混淆偽裝的隱蔽方案,本文創新性地提出了在TCP層面修改連接特征的流量隱蔽思路,表明依賴連接時長和連接數量作為特征的機器學習檢測算法是存在弱點的;
(3) 設計了基于TCP轉發的可控重連算法,實驗分析了該算法對連接時長和數據包大小的影響,為后續隱蔽信道的檢測和研究提供了新的方向。
PT通過對Tor流量進行混淆、加密、偽裝成正常協議的字段等方法,消除Tor流量的特征。PT方案和其檢測方法介紹如下。
Meek的原理是以未禁的協議作為隧道使隧道內的Tor流量通過。它采用了域前置(Domain Fronting)技術[8],利用HTTPS和CDN繞過審查。Domain Fronting指的是在DNS請求數據包和TLS的SNI字段使用未被禁止的前置域名,而在HTTP Host頭部字段使用被審查者禁止的隱藏域名。審查者只能看到前置域名,而看不到被TLS加密的HTTP中的域名。數據包到達前置域服務器(比如CDN)后,服務器解密數據包,并將其轉發到隱藏域。Meek的原理如圖1所示。

圖1 Meek原理圖
針對Meek的檢測以機器學習為主。Shahbar等[9]通過C4.5決策樹分類器,分析連接的時間跨度、連接的數量和重復性、傳輸數據量和建立的連接的數量,或者包大小、發出的字節數、最大的包大小[10],進行學習后可以識別出Meek流量。Fifield等[5]指出,正常HTTPS和Meek的TCP連接的總持續時間不同,TCP payload長度分布比例也不同。Cuzzocrea等[11]采用state-of-the-art算法(包括J48、J48Consolidated、BayesNet、jRip、OneR、REPTree法)研究了Tor流量分類問題。此外,Meek的熵值特性[12]在機器學習的檢測中也有一定效果。
除了連接相關的特征外,呼吸包也是Meek的一個特點。Meek無法由服務器主動推送消息給客戶端[12],客戶端為了獲取數據必須主動向Tor網橋發送大量心跳數據包,55%的TCP ACK包間隔小于10 ms,基本上間隔都小于1 s。
Obfs系列包括Obfs2、Obfs3、Obfs4[13]和Scramblesuit[14],目前最常使用的是Obfs4。其原理是對Tor流量加密,使之看起來像隨機字節,避免基于黑名單的指紋檢測。且Obfs4通過密鑰協商可以對抗active-probing attacks[15],防止審查者利用連接發現網橋。
在檢測方面,Wang等[12]發現基于熵的檢測和簡單啟發式算法(如長度檢測)進行聯合檢測可以識別Obfs流量。熵值的計算公式是:
(1)
式中:pi表示第i個字符出現的頻率,即該字符出現的次數除以總的字符數。熵的大小可以反映出一個數據包的字符分布是否正常。由于Obfs系列直接對傳輸的內容進行加密,因此整體流量都有著較高的熵值。而正常的協議,包括如TLS這樣的加密協議,在握手時往往有著熵值更低的明文頭部。檢測者可以對應用層第一個數據包的前2 048個字節使用熵檢測,實現對Tor的攔截。其他檢測方法還包括數據包長度檢測和截尾序貫概率比檢驗(truncated SPRT)[16]等。
FTE系列包括FTE(Format-Transforming Encryption)[6,17-18]、Stegotorus[19]、SkypeMorph[20]、CensorSpoofer[19]、Marionette[21]等。其原理是通過模仿其他協議的格式,使審查者對流量錯誤分類,從而達到躲避審查的目的。FTE通過簡單模仿HTTP流量的格式躲避審查;Stegotorus在Obfs的基礎上對包切分,改變包大小和時間、建立多個連接,并采用隱寫技術,模仿HTTP、Skype、Ventrilo等合法流量;SkypeMorph偽裝成Skype視頻流量;Marionette在FTE的基礎上加入帶有隨機性的狀態轉移,使之對于HTTP協議的模仿更逼真。
FTE只是簡單模仿協議的格式,并沒有模仿協議的語義。所以,Houmansadr等[22]提出了基于語義的方法,檢測流量與預期行為之間的差異,比如服務器能否正確返回404錯誤等。
另一方面,由于FTE的URI字段是直接加密形成的,所以也可以通過熵檢測[12]來識別FTE流量。相比正常HTTP包中的可見字符及英文單詞,FTE偽裝的HTTP包有著更高的熵值。
檢測技術[23]主要可以分為以下四類:(1) 基于語義的檢測;(2) 基于熵值的檢測;(3) 基于機器學習的檢測[24];(4) 基于DPI與防火墻的組合檢測[25-26],可以重建完整數據流,分析具體協議,對數據包進行關鍵字識別,并主動探測可疑服務器,避免誤報。這四類檢測技術中,基于熵值和DPI的檢測本質都是對數據包的內容進行分析,因此PT在進一步完善后(例如冗余處理)可以針對性地繞過它們的檢測;基于語義的檢測本質是對客戶端與服務器的交互過程進行合理性判斷,PT同樣可以在精心完善后實現繞過;而基于機器學習的檢測由于分析的是TCP連接層面的特征,層次更低,改變特征就更加困難,因而這種檢測正在逐漸成為主流的檢測手段。本文針對這種TCP層面的檢測提出了可控重連算法,通過修改TCP連接時長和包大小分布,從而形成可定制的TCP連接特征。
圖2為Tor流量隱蔽系統的部署結構,系統部署在Tor客戶端的下層,包括PT客戶端和PT服務端,充當類似Shadowsocks的角色。用戶、Tor客戶端、PT客戶端位于被審查的區域內,而PT服務端和Tor網絡位于審查區域外。

圖2 系統部署示意圖
為了方便后文描述算法,圖3展示了請求數據的流向,響應數據反之亦然。

圖3 請求數據流示意圖
Tor程序(不使用Tor時,瀏覽器產生常規HTTP/HTTPS請求)將原始請求提交給本地Socks5客戶端代理;Socks5客戶端再以Socks5協議的格式交給PT客戶端;隨后PT客戶端在{Socks5{原始請求}}的TCP流基礎上,加上流量隱蔽系統PT的封裝,繞過審查系統到達PT服務端;之后PT服務端恢復出{Socks5{原始請求}};最后同在代理服務器上的Socks5服務端解析Socks5請求并轉發到Tor網絡或目標網站。
根據Tor官方的文檔[27],Tor采用連接復用,在Tor代理中對多條TCP連接使用同一條TCP連接,因此連接時長比一般通信更長。機器學習檢測算法往往把連接時長和數據包大小等作為重要的檢測指標。由此本文提出了可控重連的算法。一方面,從TCP重連的角度,自定義PT客戶端與PT服務端之間的連接時長;另一方面,從數據包大小可控的角度,基于已有數據包的分布比例,計算轉發數據包的大小。
圖4顯示了TCP重連的基本過程,涉及以下三個重要階段。

圖4 新舊連接示意圖
1) 新連接的建立。Tor建立新鏈路或瀏覽器產生新請求時,Socks5客戶端與PT客戶端建立連接x,隨后PT客戶端與PT服務端建立連接a,PT服務端也與Socks5服務端建立連接y。在后續的重連過程中,連接x和連接y保持不變。
2) 重連的握手。PT客戶端到達預期連接時長后啟動重連,暫停向PT服務端的數據發送,對PT服務端新建連接b,并協議握手告知PT服務端,新連接b即將替換舊連接a。
3) 舊連接的揮手。PT客戶端發送FIN包關閉舊連接a,服務端也發送FIN關閉連接a后,兩者正式改用新連接b來通信。
為了兼顧轉發效率,PT服務端的主線程負責接收PT客戶端的新連接請求,而各個子線程(或稱“轉發線程”)負責進行PT客戶端與Socks5服務端之間的雙向轉發。
多線程的使用會導致同步問題,例如主線程中新連接b建立的同時,PT服務端的子線程可能正在進行舊連接a上的數據收發。因此,PT服務端不可能在新連接b建立后,立刻完成從a到b的新舊替換,所以連接a中剩余數據的讀取和連接a的完整關閉需要按照TCP四次揮手的原理進行設計。
本文的重連算法中,對于舊連接a,PT服務端在第三階段收到的來自PT客戶端的FIN包,標志著從PT客戶端到Socks5服務端方向的數據流動的停止;而PT客戶端收到PT服務端回復的FIN包后,才標志著從Socks5服務端到PT客戶端方向的數據流動的停止。此后,雙方的轉發才正式使用新連接b進行。
重連算法的關鍵是PT服務端需要正確鑒別PT客戶端在對其建立/關閉連接時的意圖,區分來自PT客戶端的新連接請求/FIN包,是重連過程中新舊連接的切換所致,還是Tor/瀏覽器在進行常規連接的建立/關閉。
對此,本文算法的核心是,PT服務端維護一個全局map,以連接y的描述符作為key,再以與PT客戶端當前連接的描述符作為value。第一階段建立連接a時,PT服務端就將連接y的信息(即key)告訴PT客戶端,那么在第二階段PT客戶端建立新連接b時,只需將連接y的信息反饋給PT服務端,就可以使其知道新舊連接a與b的對應關系,進入重連流程。從而,當PT服務端的轉發線程收到關閉連接的請求時,也可以通過查詢value是否改變,判斷當前是否正處于重連流程中。另外,PT服務端使用了全局互斥鎖,確保握手過程不會在多線程運行中被其他連接信息或重連過程打斷,也避免了map的讀寫相關性問題。
圖5描述了階段1的連接建立過程,關鍵步驟③、步驟⑤實現了PT客戶端與PT服務端之間傳遞連接y的信息。

圖5 新連接的建立
圖6描述了階段2(步驟①-步驟③)的重連過程和階段3(步驟④-步驟⑤)的舊連接關閉過程。

圖6 重連握手和舊連接揮手
為了使描述更清晰,以PT服務端主線程處理來自PT客戶端的連接請求為例,算法1給出了圖5(步驟②-步驟⑤)和圖6(步驟①-步驟③)PT服務端的偽代碼。
算法1PT服務端的main函數
輸入:收發PT客戶端。
輸出:Socks5服務端的流量。
top:
1. conn_PTc←accept_conn_from_PT_client()
2. mutex_lock()
3. handshake_msg←recv_from_PT_client()
4.ifhandshake_msg=NEW_CONNthen
5. conn_Ss←connect_Socks_server()
6. //為雙向數據傳輸創建線程
create_thread(conn_PTc,conn_Ss)
7. add_to_map {conn_Ss:conn_PTc}
8. tell_PT_client(info=conn_Ss)
9. mutex_unlock()
10.else
//重連握手
11. //從msg里提取conn_Ss信息
conn_Ss←extract(handshake_msg)
12. old_conn_PTc←query_map(key=conn_Ss)
13.ifconn_PTc≠old_conn_PTcthen
14. //用current conn_PTc替換舊值
renew_map {conn_Ss:conn_PTc}
15. tell_PT_client(MAP_RENEW_OK)
16. mutex_unlock()
17.elseerror()
18.endif
19.endif
20.gototop
數據包可控算法研究了在已知正常流量的數據包大小分布的情況下,如何改變轉發數據包的大小,使其與正常流量相似。由于改變一個數據包大小的方式只有拆分和冗余兩種,故算法的目標是在使轉發數據包大小符合正常流量分布比例的同時,盡可能減小拆分和冗余對信道與時間的浪費。
設通過抓包等前期手段,已知一段時間內正常流量的數據包大小分布如圖7(a)所示,大小在ci-1~ci范圍(記為區間i)的有yi個數據包(共n個區間),當前待轉發的原始數據包大小為x,算法完成后實際發送的稱為結果數據包。

(a) 正常流量的數據包大小分布

(b) 權值序列與當前數據包的關系圖7 當前數據包與正常流量分布和權值序列的關系
算法需要考慮如下幾點:(1) 結果數據包的大小分布應當接近正常流量數據包的大小分布,同時要保持一定的隨機性;(2) 為了節省信道資源,需要適當減少拆分和冗余次數;(3) 如果要冗余處理,應當避免結果數據包的大小和原始數據包相差過多,比如原始數據包大小在區間i內,那么同樣條件下計算結果數據包在區間i+1的概率應當比在區間i+5的概率大;(4) 如果要拆分,將一個數據包拆成比原始數據包略小的包意義不大,反而造成浪費,所以假設原始數據包在區間i內,那么結果數據包在區間i-1的概率應該適當減小。
根據上述要求,算法的過程如下:
1) 找到x所屬的大小范圍xi∈[ci-1,ci),即區間i。
2) 根據i,對表示正常數據包大小分布的y序列乘以一定權值得到y′序列,用來計算臨時概率:

(2)
3) 根據y′序列,按概率生成結果數據包所屬的區間i′,例如結果數據包仍在i區間的概率為:
(3)
隨后根據i′和i的大小關系決定拆分或者冗余:
(1) 如果i′等于i,則直接發送,無須處理;(2) 如果i′落在大于i區間,表明結果數據包比原始數據包大,應加冗余;(3) 如果i′落在小于i區間,則需要拆分成兩個包,計算原始數據包和預期結果數據包大小的差值,得到預期結果包1(區間i)和差值結果包2(由差值確定)。由于差值結果包2并不是主動計算概率得到,而是被動生成的,所以在對應區間的y序列值減1,減小后續數據包落入該區間的概率。
算法中值得關注的是β和α序列的取值,如圖7(b)所示,假設原始數據包x在c3~c4范圍,計算y′序列時的權值序列應當如圖中那樣,β應小于1,減少不必要的拆包;α序列應當是遞減序列,在α0處是最大值,并逐漸趨近于一個略小于1的值b。本文算法中,α序列采用式(4)得到,其中Δi指區間序號與原始數據包所屬區間i的差值:
αΔi=ae-Δi+b(a>1,0
(4)
即α0=a+b,α1=ae-1+b,α2=ae-2+b,…。
由此得到算法第2步中計算y′序列時的權值。
算法2描述了生成結果數據包的大致過程。
算法2根據正常數據包大小生成結果數據包
輸入:原始包大小before_size;分布序列y在區間i有yi個正常數據包;參數β、a、b。
輸出:{after_i,another_i},結果數據包所屬的區間(假設共有N個區間)。
1. before_i←before_size.region()
2.y′ ←deepcopy(y)
4.forj=0:N-before_i-1do
6.endfor
7. //根據y′序列和隨機值產生結果數據包的區間
after_i←rand_region(y′)
8.ifafter_i=before_ithen
9.return{after_i,None}
//直接發送
10.elseifafter_i>before_ithen
11.return{after_i,None}
//加冗余
12.else
//拆分成兩個數據包
13. another_i←calc_difference_i(before_size,after_i)
14. //因被動產生的結果包調整y序列
y.adjust(another_i)
15.return{after_i,another_i}
16.endif
根據可控重連算法,分別針對連接時長和數據包大小的計算進行了如下實驗。
圖8對比了重連前后的連接時長。實驗在局域網的兩臺主機上完成,主機1訪問視頻網站(2分鐘視頻)產生連接時長超過10 s的原始流量。使用重連算法時,主機1部署PT客戶端(PT客戶端對超過10 s的連接啟動重連),主機2部署PT服務端,配合PT客戶端實現重連。

圖8 重連前后的連接時長對比圖
可以看出,不使用重連時,存在超過10 s的連接,最長的持續了整個實驗過程;而使用重連算法后,時長在10~20 s范圍的連接數量增加(實際上時長集中于10 s左右,且都小于11 s),超過此范圍的連接數量為0,實現了秒級精度的控制,表明重連算法取得了理想效果。
圖9對比了數據包大小可控算法前后的數據包大小與累積分布函數CDF的關系,實驗中參數β取0.6,a取2,b取0.8。為使仿真結果更貼近實際,實驗中原始數據包CDF的來源為3分鐘內訪問YouTube視頻的Tor下行流量,正常流量CDF來源為3分鐘內直接訪問YouTube視頻的下行流量。

圖9 數據包大小可控算法結果圖
可以看出,原始數據包和結果數據包的比例分布在大于1 280字節時有較大不同,而結果數據包和正常流量分布的折線非常接近,說明可控算法對原始數據包的大小進行了有效調整。
可用余弦相似度進一步分析結果流量與正常流量的接近程度,給定兩個序列A和B,其余弦相似性θ由點積和向量長度給出,越接近1表示越相似:
(5)
表1給出了不同β、a、b取值時的結果包數量、總計冗余次數、總計冗余跨度(比如原始包在區間i,結果包在區間i+3,則冗余區間跨度為3)和相似度值。原始數據包數量為7 741個。

表1 不同β,a,b取值的結果數據包
以β取0.6、a取2、b取0.8為例,約8%的數據包經歷了拆分,不到一半的數據包經歷了冗余處理,平均每次冗余跨1至2個區間,這樣的拆分和冗余處理是可以接受的,同時相似度也較高,達到了預期需求。表1中,β取值無明顯的影響;a的增大會減少拆分和冗余情況,但會降低相似度;b的增大會減少拆分,增加冗余,提高相似度;若不考慮權值因素(即表中最后一行)直接按照正常流量的分布比例計算概率,會導致更多的拆分和冗余出現。
本文分析了已有的Tor隱蔽方案和對應的檢測算法;針對TCP連接層面的Tor流量特征提出了一種新的流量隱蔽思路;通過可控重連算法實現了對TCP連接時長的控制;研究了調整數據包大小使其符合正常流量數據包大小分布的方案;為流量隱蔽的研究提供了新方向。
在本文基礎上,未來可從以下兩個方向開展進一步研究:(1) 高丟包率的網絡環境會影響TCP連接的數據通信和四次揮手,使連接時長超過預期。未來可以研究惡劣網絡環境的優化重連算法,除了從重連協議的角度進行設計,也可以引入對歷史實際重連時長的統計,計算重連計時的提前量。(2) 研究不同應用在連接時長和數據包分布上的規律,設計能夠定制連接特征的可控重連算法。將優化后的算法部署到海外云服務器上,加上基本的混淆功能,測試實際Tor流量和偽裝后流量的差別。