基於 TLS 1.3 的網域前置

介紹

基於 TLS 1.3 的網域前置
來自 Cisco、BlueCoat、FireEye 等知名製造商的現代企業內容過濾系統與其更強大的同類產品 - DPI 系統有很多共同點,DPI 系統正在國家層面積極實施。 兩者工作的本質都是檢查傳入和傳出的網路流量,並根據黑/白名單做出禁止網路連線的決定。 由於它們在工作的基礎上都依賴相似的原則,因此規避它們的方法也有很多共同點。

域前端技術是允許您非常有效地繞過 DPI 和公司係統的技術之一。 其本質是,我們訪問一個被阻止的資源,隱藏在另一個具有良好聲譽的公共域後面,該域顯然不會被任何系統阻止,例如google.com。

關於這項技術已經寫了很多文章,並且給了許多例子。 然而,最近流行的 DNS-over-HTTPS 和加密 SNI 技術,以及新版本的 TLS 1.3 協議,使得考慮域前置的另一種選擇成為可能。

了解技術

首先,讓我們定義一些基本概念,以便每個人都了解誰是誰以及為什麼需要這一切。 我們提到了eSNI機制,其操作將進一步討論。 eSNI(加密伺服器名稱指示)機制是 SNI 的安全版本,僅適用於 TLS 1.3 協定。 主要思想是加密有關請求發送到哪個域的信息等。

現在我們來看看eSNI機制在實際中是如何運作的。

假設我們有一個被現代 DPI 解決方案封鎖的網路資源(例如,著名的 torrent 追蹤器 rutracker.nl)。 當我們嘗試造訪 torrent 追蹤器的網站時,我們會看到提供者的標準存根,表示該資源已被封鎖:

基於 TLS 1.3 的網域前置

在 RKN 網站上,該網域實際上列在停止清單中:

基於 TLS 1.3 的網域前置

當你查詢whois時,你可以看到網域本身「隱藏」在雲端供應商Cloudflare後面。

基於 TLS 1.3 的網域前置

但與RKN 的「專家」不同,Beeline 的技術更精明的員工(或者是受到我們著名監管機構的慘痛經驗的教訓)並沒有愚蠢地通過IP 地址禁止該網站,而是將域名添加到停止列表中。 如果您查看同一 IP 位址後面隱藏的其他網域,請訪問其中一個網域並查看存取未被阻止,則可以輕鬆驗證這一點:

基於 TLS 1.3 的網域前置

這是怎麼發生的? 由於所有通訊都是透過 https 協定進行的,而且我們還沒有註意到 Beeline 的 https 憑證被替換,所以提供者的 DPI 如何知道我的瀏覽器位於哪個網域? 是他有千里眼還是我被跟蹤了?

讓我們嘗試透過wireshark查看流量來回答這個問題

基於 TLS 1.3 的網域前置

螢幕截圖顯示,首先瀏覽器透過 DNS 取得伺服器的 IP 位址,然後與目標伺服器進行標準 TCP 握手,然後瀏覽器嘗試與伺服器建立 SSL 連線。 為此,它會傳送 SSL 用戶端 Hello 封包,其中包含明文形式的來源網域名稱。 cloudflare 前端伺服器需要此欄位才能正確路由連線。 這就是提供者 DPI 捕獲我們並中斷我們連接的地方。 同時,我們沒有收到來自提供者的任何存根,並且我們看到標準瀏覽器錯誤,就好像該網站已被停用或根本無法運作:

基於 TLS 1.3 的網域前置

現在讓我們在瀏覽器中啟用eSNI機制,如說明所寫 火狐瀏覽器 :
為此,我們打開 Firefox 設定頁面 about:config中 並啟動以下設定:

network.trr.mode = 2;
network.trr.uri = https://mozilla.cloudflare-dns.com/dns-query
network.security.esni.enabled = true

之後,我們將檢查 cloudflare 網站上的設定是否正常運作。 鏈接 讓我們再次嘗試我們的 torrent 追蹤器的技巧。

基於 TLS 1.3 的網域前置

瞧。 我們最喜歡的追蹤器在沒有任何 VPN 或代理伺服器的情況下開啟。 現在讓我們來看看wireshark 中的流量轉儲,看看發生了什麼。

基於 TLS 1.3 的網域前置

這次,ssl 用戶端 hello 套件沒有明確包含目標網域,而是套件中出現了一個新欄位 - crypto_server_name - 這是包含 rutracker.nl 值的位置,只有 cloudflare 前端伺服器可以解密該欄位場地。 如果是這樣,那麼提供者 DPI 別無選擇,只能洗手並允許此類流量。 沒有其他加密選項。

因此,我們研究了該技術在瀏覽器中的工作原理。 現在讓我們嘗試將其應用到更具體、更有趣的事情上。 首先,我們將教導同一個curl使用eSNI來與TLS 1.3配合使用,同時我們將了解基於eSNI的域前端本身是如何運作的。

使用 eSNI 進行域前置

由於curl使用標準openssl函式庫透過https協議進行連接,因此首先我們需要在那裡提供eSNI支援。 openssl master 分支還沒有 eSNI 支持,所以我們需要下載一個特殊的 openssl 分支,編譯並安裝它。

我們從 GitHub 克隆儲存庫並照常編譯:

$ git clone https://github.com/sftcd/openssl
$ cd openssl
$ ./config

$ make
$ cd esnistuff
$ make

接下來,我們使用curl克隆儲存庫並使用我們編譯的openssl程式庫配置其編譯:

$ cd $HOME/code
$ git clone https://github.com/niallor/curl.git curl-esni
$ cd curl-esni

$ export LD_LIBRARY_PATH=/opt/openssl
$ ./buildconf
$ LDFLAGS="-L/opt/openssl" ./configure --with-ssl=/opt/openssl --enable-esni --enable-debug

在這裡,正確指定 openssl 所在的所有目錄(在我們的範例中為 /opt/openssl/)並確保設定過程順利進行非常重要。

如果配置成功,我們會看到這樣一行:

警告:esni ESNI 已啟用,但標記為“實驗”。 謹慎使用!

$ make

成功建置套件後,我們將使用 openssl 中的特殊 bash 檔案來配置和運行curl。 為了方便起見,我們用curl將其複製到目錄中:

cp /opt/openssl/esnistuff/curl-esni 

並向 cloudflare 伺服器發出測試 https 請求,同時在 Wireshark 中記錄 DNS 和 TLS 封包。

$ ESNI_COVER="www.hello-rkn.ru" ./curl-esni https://cloudflare.com/

在伺服器回應中,除了來自openssl和curl的大量偵錯資訊之外,我們還將收到來自cloudflare的帶有代碼301的HTTP回應。

HTTP/1.1 301 Moved Permanently
< Date: Sun, 03 Nov 2019 13:12:55 GMT
< Transfer-Encoding: chunked
< Connection: keep-alive
< Cache-Control: max-age=3600
< Expires: Sun, 03 Nov 2019 14:12:55 GMT
< Location: https://www.cloudflare.com/

這表示我們的請求已成功傳遞到目標伺服器、被聽到並被處理。

現在讓我們來看看wireshark中的流量轉儲,即提供者 DPI 在這種情況下看到了什麼。

基於 TLS 1.3 的網域前置

可以看到,curl 首先向 DNS 伺服器尋求 cloudflare 伺服器的公共 eSNI 金鑰——對 _esni.cloudflare.com(包號 13)的 TXT DNS 請求。 然後,使用 openssl 函式庫,curl 向 cloudflare 伺服器發送 TLS 1.3 請求,其中 SNI 欄位使用上一個步驟中獲得的公鑰(資料包 #22)進行加密。 但是,除了 eSNI 欄位之外,SSL-hello 資料包還包含一個通常的欄位 - open SNI,我們可以按任何順序指定該欄位(在本例中 - www.hello-rkn.ru).

Cloudflare 伺服器處理時不會以任何方式考慮此開放 SNI 字段,並且僅充當提供者 DPI 的遮罩。 cloudflare 伺服器收到我們的 ssl-hello 封包,解密 eSNI,從那裡提取原始 SNI 並處理它,就像什麼都沒發生一樣(它完全按照開發 eSNI 時計劃的那樣進行)。

在這種情況下,從 DPI 的角度來看,唯一可以捕獲的是對 _esni.cloudflare.com 的主 DNS 請求。 但我們開放 DNS 請求只是為了展示機制如何從內部運作。

為了最終擺脫 DPI 的困擾,我們使用了已經提到的 DNS-over-HTTPS 機制。 一點解釋 - DOH 是一種協議,可讓您透過 HTTPS 發送 DNS 請求來防止中間人攻擊。

讓我們再次執行請求,但這次我們將透過 https 協定而不是 DNS 接收公共 eSNI 金鑰:

ESNI_COVER="www.hello-rkn.ru" DOH_URL=https://mozilla.cloudflare-dns.com/dns-query ./curl-esni https://cloudflare.com/

請求流量轉儲如下圖所示:

基於 TLS 1.3 的網域前置

可以看到,curl先透過DoH協定存取mozilla.cloudflare-dns.com伺服器(https連接伺服器104.16.249.249),從中取得用於SNI加密的公鑰值,然後到達目的地伺服器,隱藏在網域後面 www.hello-rkn.ru.

除了上面的 DoH 解析器 mozilla.cloudflare-dns.com 之外,我們還可以使用其他流行的 DoH 服務,例如來自著名的邪惡公司的服務。
讓我們執行以下查詢:

ESNI_COVER="www.kremlin.ru" DOH_URL=https://dns.google/dns-query ./curl-esni https://rutracker.nl/

我們得到了答案:

< HTTP/1.1 301 Moved Permanently
< Date: Sun, 03 Nov 2019 14:10:22 GMT
< Content-Type: text/html
< Transfer-Encoding: chunked
< Connection: keep-alive
< Set-Cookie: __cfduid=da0144d982437e77b0b37af7d00438b1a1572790222; expires=Mon, 02-Nov-20 14:10:22 GMT; path=/; domain=.rutracker.nl; HttpOnly; Secure
< Location: https://rutracker.nl/forum/index.php
< CF-Cache-Status: DYNAMIC
< Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
< Server: cloudflare
< CF-RAY: 52feee696f42d891-CPH

基於 TLS 1.3 的網域前置

在這種情況下,我們轉向被封鎖的rutracker.nl伺服器,使用DoH解析器dns.google(這裡沒有拼寫錯誤,現在著名的公司有自己的一級網域)並用另一個網域覆蓋我們自己,這是嚴格的禁止所有 DPI 封鎖,違者處死。 根據收到的回复,您可以了解我們的請求已成功處理。

作為對提供者的 DPI 回應開放 SNI(我們將其作為掩護進行傳輸)的額外檢查,我們可以以其他一些禁止資源(例如另一個「良好」的 torrent 追蹤器)為幌子向 rutracker.nl 發出請求:

$ ESNI_COVER="rutor.info" DOH_URL=https://dns.google/dns-query ./curl-esni https://rutracker.nl/

我們不會收到伺服器的回應,因為...... 我們的請求將被 DPI 系統阻止。

第一部分的簡短結論

因此,我們能夠使用 openssl 和curl 來示範 eSNI 的功能,並測試基於 eSNI 的域前置操作。 以同樣的方式,我們可以調整我們最喜歡的使用 openssl 庫的工具,以「在其他網域的幌子下」工作。 有關此內容的更多詳細信息,請參閱我們的下一篇文章。

來源: www.habr.com

添加評論