交流評論、關注點贊

  • Facebook Icon臉書專頁
  • telegram Icon翻牆交流電報群
  • telegram Icon電報頻道
  • RSS訂閱禁聞RSS/FEED訂閱

報告:中國的防火長城已經封鎖加密伺服器名稱指示(ESNI)

2020年08月21日 16:10 PDF版 分享轉發

我們於2020年7月30日報告 (存檔)中國封鎖了帶有ESNI擴展的TLS連接。初次封鎖見於2020年7月29日。

我們確認)已經開始封鎖ESNI這一TLS1.3和HTTPS的基礎特性。我們在本文中實證性地展示如何觸發審查,並研究」殘餘審查」的延續時長。 我們還將展示7種用Geneva發現的基於客戶端或服務端的繞過審查策略。

什麼是加密伺服器名稱指示(ESNI)?

TLS是網路通訊的安全基礎(HTTPS)。TLS提供的認證加密使得用戶可以確定他們在與誰通訊, 並確保通訊信息不被中間人看到或篡改。 雖然TLS可以隱藏用戶通訊的內容,但其並不能總是隱藏與用戶通訊的對象。 比如TLS握手可以攜帶一個叫做加密伺服器名稱指示(SNI)的擴展, 這個擴展幫助客戶端告訴伺服器其想要訪問的網站的域名。 包括中國在內的審查者利用這一擴展來檢查並阻止用戶訪問特定的網站。

廣告:
搬瓦工翻牆 Just My Socks

電腦翻牆軟體

短網址:https://git.io/jww

安卓翻牆APP下載

自建翻牆伺服器教程

TLS1.3引入了加密SNI(ESNI)。 簡而言之就是用加密了的SNI阻止中間人查看客戶端要訪問的特定網站。 (更多ESNI的益處請見Cloudflare的介紹文章)。 ESNI有讓審查HTTPS流量變得更加困難的潛能; 因為不知道用戶使用ESNI訪問的網站,審查者要麼不封鎖任何ESNI連接,要麼封鎖所有的ESNI連接。 我們現在確認中國的審查者選擇了後者。

主要結論

  • GFW通過丟棄從客戶端到伺服器的數據包來阻止ESNI連接。
  • 封鎖可以從GFW內外雙向觸發。
  • 0xffce擴展標識是觸發封堵的必要條件。
  • 封鎖可以發生在1到65535的所有埠上。
  • 一旦GFW阻斷了一個連接,殘留的審查就會繼續阻斷與(原IP,目標IP,目標埠)三元組相關的所有TCP流量,持續120或180秒。
  • 我們已經發現了6種可以部署于客戶端和4種可以部署于服務端的規避策略。

我們是怎麼知道的?

我們寫了一個簡單的Python程序,它可以:

  1. 完成與指定伺服器的TCP握手;
  2. 然後發送一個帶有ESNI擴展名的TLS ClientHello消息;ClientHello的指紋和Firefox 79.0所發送的一樣正常。

我們讓程序發送帶有ESNI的ClientHello消息。我們既嘗試了從牆內向牆外發送,也嘗試了從牆外向牆內發送。我們同時採集客戶端和服務端兩邊的流量進行分析,我們確保發送ClientHello的伺服器會完成TCP握手,但不會向客戶端發送任何數據包,也不會首先關閉連接。所有的實驗都在7月30日到8月6日之間進行。

關於封鎖的細節

通過丟棄數據包來阻止,而不是注入RST

對比兩端捕獲的流量,我們發現GFW通過丟棄從客戶端到伺服器的數據包來阻止ESNI連接。

這與GFW對其他常用協議的阻斷方式有兩點不同。 首先,GFW審查SNI和HTTP的方式是向伺服器和客戶端注入偽造的TCP RST。但是我們沒有觀察到GFW注入任何數據包來阻斷ESNI流量。其次,GFW通過丟棄伺服器到客戶端的流量封鎖Tor和伺服器的埠和IP;然而,GFW會丟棄客戶端到伺服器的ESNI流量。

我們還注意到,GFW在丟棄TCP包時,並不區分TCP包的標誌。(這與伊朗的一些審查系統不同,後者不丟棄帶有RST或FIN標誌的數據包。)

封堵可以雙向觸發

我們發現封堵是可以雙向觸發的。 換句話說,從外向防火牆內發送一個ESNI握手,和從防火牆內向外發送一樣,都可以觸發審查。

得益於這種雙向性,人們可以在不控制任何位於中國的伺服器的情況下,從GFW外部遠程測試這種基於ESNI的審查。 我們指出,除了ESNI審查外,GFW對DNS、HTTP、SNI、FTP、SMTP和Shadowsocks的審查也可以從牆外進行測量。

GFW對ESNI進行審查,但不封鎖沒有SNI擴展的ClientHello

我們確認沒有ESNI和SNI擴展的TLS ClientHello不能觸發封鎖。 換句話說,encrypted_server_name 擴展的 0xffce 擴展標識是觸發封堵的必要條件。

我們將ClientHello中的0xffce替換為0x7777然後進行測試。替換后,發送這樣的ClientHello就不能再觸發封鎖了。

這個確認是很重要的,因為有人觀察到其他審查者可能會屏蔽任何沒有SNI擴展的ClientHello消息,這將導致ESNI和無SNI都會被屏蔽。

新的擴展值還未被封鎖

riseup pad上的匿名人士指出, 現有的ESNI使用0xffce作為擴展值(詳見 Section 8.1)。 但時新的ECH使用0xff02,0xff03和0xff04作為擴展值(Section 11.1). 我們確認這些新的擴展值還未被封鎖。

具體而言, 我們把一個能夠觸發審查的ClientHello的0xffce替換為了0xff02,0xff03和0xff04。 發送修改後的ClientHello不能觸發審查。

GFW需要看到一個完整的TCP握手以觸發ESNI封鎖

我們發現GFW需要看到一個完整的TCP握手以觸發ESNI封鎖。

我們從外部對中國的伺服器進行了兩次實驗。在第一個實驗中,在沒有發送任何SYN包的情況下,我們的客戶端每2秒發送一個帶ESNI擴展的ClientHello消息。在第二個實驗中,我們的客戶端每2秒發送一個SYN數據包和一個帶ESNI擴展的ClientHello消息;但伺服器不會響應任何數據包(也不會發送SYN+ACK來完成握手)。

在每次實驗中,我們都發送了10條ClientHello消息。結果發現沒有觸發過任何審查或殘餘審查。所有的ClientHello消息實際上都到達了伺服器。這個結果表明,在觸發基於ESNI的審查之前,TCP握手是必要條件。 這也表明,與GFW基於SNI的審查機類似,ESNI的審查機也是有狀態的。

封鎖發生在所有埠上

我們發現ESNI封鎖不僅會發生在443埠,也會發生在1到65535的所有埠。

具體來說,我們從外部向中國伺服器的1-65535的每個埠連續發送了兩次ESNI握手。 對於每個埠,我們先發送一次ESNI握手;然後在連接超時后(20秒后),我們再嘗試與伺服器完成一次TCP握手。如果第二次沒有收到伺服器發來的SYN+ACK,我們就認為該埠被封鎖了。 結果是,在1到65535的所有埠上都觀察到了對ESNI的封鎖。這個特性可以讓我們高效地測試ESNI封鎖,因為我們可以對同一IP地址的多個埠進行同時測試。

審查殘留

我們發現在阻斷ESNI握手后,GFW會繼續阻斷與(源IP,目標IP,目標埠)3元組相關的任何連接一段時間。確切的審查殘留時間可能會有所不同。我們觀察到它有時持續120秒,有時持續180秒。我們注意到,在殘留審查時間內發送額外的ESNI握手不會重置審查持續的定時器。這與之前觀察到的基於SNI的攔截GFW的殘餘審查類似;而且它與伊朗的殘餘審查不同,在伊朗,定時器將被重置。

這些發現部分基於以下實驗。從外部,我們每秒向中國伺服器的443埠發送一條ClientHello消息。 第一秒,第二秒和第121秒的TCP握手被接受。其他所有的握手嘗試都不成功,因為由於殘留的審查,SYN包甚至沒有到達伺服器。

這個結果表明,與之前發現的GFW對SNI的殘留審查類似,GFW也對ESNI也採用了殘留審查。此外,第二秒的握手可以完成,意味著GFW至少需要1秒的時間來反應並啟用攔截規則。

如何規避封鎖?

Geneva(Genetic Evasion)是我們中位於馬里蘭大學的研究人員開發的一種遺傳演算法,它在進化過程中自動發現新的審查規避策略。 它在不影響原始連接的前提下,通過注入、替換、分割或丟棄數據包流來迷惑審查者。 與大多數反審查系統不同的是,它不需要在連接的兩端都進行部署:它只在一方(客戶端或伺服器)運行。

Geneva利用審查機器來實時地訓練自己的遺傳演算法。 截至今日,其已經找到了許多可以規避不同國家審查的策略。 Geneva的審查規避策略描述了應該如何修改流量。 由於Geneva將不斷發展這些策略,因此它們用領域特定語言(domain-specific language)來表達,這些語言構成了每個策略的 「DNA」。(關於Geneva的完整代碼及文檔,請參見我們的Github頁面)。

要了解更多關於Geneva(或Geneva策略引擎)工作原理的信息,請參閱我們的論文或關於頁面。

為了讓Geneva能夠直接利用GFW對ESNI審查進行訓練,我們寫了一個自定義的插件來執行以下步驟。

  1. Geneva在位於牆外的TCP伺服器上隨機開放一個埠。隨機開放埠是為了避免此前審查的殘留。
  2. Geneva驅動一個位於中國境內的TCP客戶端連接到伺服器。
  3. 客戶端發送一個帶有加密SNI(ESNI)擴展的TLS 1.3 ClientHello。
  4. 客戶端休眠2秒,等待GFW審查機制啟動。
  5. 客戶端發送一個簡短的測試消息”test”來測試是否已經被審查。
  6. 重複步驟4和5。
  7. 伺服器確認是否收到了客戶端發送的完整的TLS ClientHello以及測試消息。如果收到了,該策略就會得到正向的適合度獎勵;如果沒有收到(或者客戶端在發送測試消息時超時了),該策略就會受到懲罰。

利用這個適合度函數,Geneva可以直接針對ESNI審查制度測試和訓練策略。 在短短几個小時內,它就發現了多個繞過審查的策略。在本節中,我們將詳細描述它們。

Geneva策略引擎在我們的Github上是開源的,所以所有這些策略都可以被任何人部署和使用。由於它們在 TCP 層運行,因此可以應用於任何需要使用 ESNI 的應用程序:隨著 Geneva 的運行,即使是未經修改的網路瀏覽器也可以成為一個簡單的審查規避工具。

請注意,Geneva不是通用的翻牆軟體,也不提供任何額外的加密、隱私或保護。它是一個測試版的研究原型,而且它並沒有針對速度進行優化。使用這些策略,風險自擔。

策略

我們在48小時的時間里,從客戶端和伺服器端對Geneva進行了訓練。我們總共發現了6種策略來打敗對ESNI的封鎖機制。其中有4個可以在伺服器端使用,所有6個都可以在客戶端使用。

以下是TCP層的策略,只需部署在客戶端,即可擊敗針對ESNI的封鎖。

策略 1: 三重 SYN

第一種客戶端策略的工作原理是用三個SYN數據包啟動TCP的三次握手,這樣第三個SYN的序列號就是錯誤的。

在Geneva的語法中,這個策略是這樣的:

[TCP:flags:S]-duplicate(duplicate,tamper{TCP:seq:corrupt})-| \/

這種策略是對於GFW的跳出同步攻擊(synchronization attack)。GFW會轉而追蹤這個新的錯誤序列號,而錯過ESNI請求。

這個策略也可以部署在服務端:

[TCP:flags:SA]-tamper{TCP:flags:replace:S}(duplicate(duplicate,tamper{TCP:seq:corrupt}),)-| \/

雖然這種策略使得伺服器永遠不會發送SYN+ACK數據包,但這並不會破壞三次握手。在三次握手過程中,伺服器沒有像往常一樣發送一個SYN+ACK數據包,而是發送三個SYN數據包(第三個數據包的校驗和是錯誤的)。

第一個SYN數據包的作用是啟動TCP的同步打開(Simultaneous Open),這是所有主流操作系統都支持的一個古老的TCP功能,用於處理兩個TCP棧同時發送SYN數據包的情況。當客戶端收到伺服器發送的SYN時,客戶端發送一個 SYN+ACK 數據包,伺服器響應一個 ACK 來完成握手。這樣就有效地將傳統的三次握手改為四次握手。帶有損壞序列號的SYN使GFW跳出同步(但被客戶端忽略),成功地擊敗了封鎖機制的同時並不傷害到原有連接。

策略2:四位元組分割

我們發現的下一個策略也可以從客戶端或伺服器使用。在這個策略中,客戶端將ESNI請求分為兩段TCP發送,第一段TCP的長度小於或等於4個位元組。

客戶端策略的Geneva語法是這樣的: [TCP:flags:PA]-fragment{tcp:4:True}-| \/

這已經不是Geneva第一次發現分段策略,但令人驚訝的是,這種策略在中國竟然有效。畢竟防火長城擁有著名的TCP重建能力已經有近十年了(見brdgrd)。TLS頭是5個位元組長,所以我們推測,像這樣將TLS頭分割到多個數據包中,打破了GFW將包含ESNI的數據包識別為TLS的能力。這對GFW如何通過指紋識別連接有有趣的影響:它表明GFW中負責識別的組件並不能從TCP層面中重組所有的上層協議。這一理論得到了Geneva過去所發現的其他基於分段的策略的支持(詳見這篇論文)。

這個策略也可以從伺服器端觸發。通過在三次握手期間減少TCP窗口大小,伺服器可以強制客戶端分割請求。在Geneva的語法中,可以通過以下方式實現:[TCP:flags:SA]-tamper{TCP:window:replace:4}-| \/

策略3:TCB Teardown

下一個策略是經典的TCB(TCP Control Block)Teardown:客戶端向連接中注入一個帶有錯誤的校驗和的RST數據包。這將欺騙GFW,使其認為連接已被中斷。

在Geneva的語法中,這個策略看起來是這樣的: [TCP:flags:A]-duplicate(,tamper{TCP:flags:replace:RA}(tamper{TCP:chksum:corrupt},))-| \/

TCB Teardowns並不是什麼新鮮事:Khattak et al.在幾乎十年前就已經演示過了,Geneva過去也多次發現了針對GFW的Teardown攻擊。

令人驚訝的是,這種策略也可以從伺服器端誘導。 在三次握手過程中,伺服器可以發送一個帶有錯誤ACK的SYN+ACK數據包,從而誘導客戶端發送RST。這將導致RST的序列號不正確(ACK為0,但仍足以引起TCB Teardown)。

策略4:FIN+SYN

下一個策略似乎是另一種角度的跳出同步攻擊。在這一策略中,客戶端(或伺服器)發送一個數據包,在三次握手過程中同時設置 FIN 和 SYN。 客戶端的Geneva語法是[TCP:flags:A]-duplicate(tamper{TCP:flags:replace:FS},)-| \/ 服務端的Geneva語法是 [TCP:flags:SA]-duplicate(tamper{TCP:flags:replace:FS},)-| \/

在過去,我們發現GFW在對其他協議進行審查時,對FIN數據包有特殊的處理。 似乎FIN的出現會使GFW立即同步到對當前連接的跟蹤,但SYN的出現會使它認為實際的序列號與實際值相差+1,使GFW與實際連接偏離1。

我們對以上假設進行了測試:在這個策略運行的時候,將客戶端實際請求的序列號增加1后,連接被阻斷了。

在服務端,這個策略不需要FIN就可以運行。

策略5:TCB Turnaround

TCB Turnaround策略很簡單:在客戶端發起三次握手之前,首先向伺服器發送一個SYN+ACK數據包。SYN+ACK使讓GFW混淆了客戶機和伺服器的角色,從而使客戶端能夠不受阻礙地進行通信。TCB Turnaround攻擊在哈薩克仍然有效,但在GFW上,TCB Turnaround攻擊對其他協議不起作用。

在Geneva的語法中:[TCP:flags:S]-duplicate(tamper{TCP:flags:replace:SA},)-| \/

該策略只適用於客戶端,因為當SYN數據包到達伺服器時,GFW已經知道哪一方是客戶端了。

策略6:TCB 跳出同步

最後,Geneva發現了簡單的基於載荷的TCB跳出攻擊。從客戶端,注入一個帶有載荷和錯誤的校驗和的數據包就足以使GFW跳出對當前連接的同步。 Geneva在研究GFW對其他協議的審查時,已經發現過這一策略了。

Geneva的語法是這樣的 [TCP:flags:A]-duplicate(tamper{TCP:load:replace:AAAAAAAAAA}(tamper{TCP:chksum:corrupt},),)-|

這個策略不能在伺服器端使用。

對審查規避策略的總結

我們已經找到6種可以部署在客戶端,和4種可以部署在服務端的審查規避策略。 每一種都有近乎100%的可靠性,並可以用於規避針對ESNI的審查。 遺憾的是,這些策略並非是一勞永逸的:就像貓捉老鼠一般,防火長城也會繼續提升其審查能力。

未解決的問題

我們仍不清楚為和會觀察到不同的殘餘審查時長。 與所有類似研究一樣,在與我們所用節點不同的中國地區,可能存在著不同於我們所觀察到的審查的方式。 如果你觀察到了不同與上述的審查方式,或者我們的審查規避策略對你並不奏效, 盡請聯繫我們。

鳴謝

我們想在此感謝所有在riseup留言板上提問,反饋和建議的匿名人士。 這些評論幫助我們給予社區所最關心的問題更高的優先順序,並從而加速了我們的研究。

我們還感謝OONI和OTF社區所有人的支持。

聯繫我們

Geneva團隊:

  • Kevin Bock (PGP key)
  • Dave Levin (PGP key)

GFW Report:

  • Anonymous (PGP key)
  • Amir Houmansadr (PGP key)

iYouPort:

  • onoketa (PGP key)

我們在censorship.ai,iyouport.org,gfw.report,net4people和ntc.party上同步更新了這篇報告。
來源:iyouport.org

喜歡、支持,請轉發分享↓Follow Us 責任編輯:藍柱