逆向工程:揭示Google Colab未公開的祕密

語言: CN / TW / HK

來源|Open Source Data Science Tools\ 翻譯|程浩源

Google Colaboratory,簡稱 “Colab” ,是一個免費的Jupyter notebook雲平臺。Colab 不僅可以為使用者提供 Python 和 R notebooks 的執行環境,而且還允許使用者免費共享部分 GPU 和 TPU 資源。

對於負責在 Jupyter Notebook 程式設計的資料科學家來說,Colab早已成為了預設的執行環境。然而,將 Colab 的算力運用到除 Jupter Notebooks 以外的其他應用,則是一件極其困難的事。

對於那些想生產模型,並將其帶出Notebook階段的機器學習工程師而言,這樣的問題尤為明顯。雖然 Notebooks 非常適合用來探索,但將它與訓練過程編入正式流水線的高階MLOps工具一起使用時,效果不佳。

在遇到類似問題後,我決定不讓 Colab 的侷限性改變我的工作流程,而是嘗試圍繞我的工作流程去改變 Colab!

出於這個原因,今天我們將探究 Google Colab 的內部結構,並嘗試稍微改變 Colab 的內建規則。需要提前宣告的是,我們只是想探究 Colab,不會對 Colab 本身或者它的使用者造成任何影響。

1

揭開幕後的祕密

Colab 的祕密在於它的後端:谷歌伺服器為 Colab 提供基礎設施支援,讓使用者可以輕鬆執行程式碼。因此,我們第一步先分析 Colab 的 API,最簡單的方法是檢查 Colab 在正常執行期間進行的 API 呼叫。

首先開啟谷歌開發者工具,找到網路(Network)選項,然後執行一段程式碼,開發者工具開始記錄 Colab 發出的每個請求,然後我們發現了一些有趣的東西。

看上去這個URL(/tun/m//socket.io)是遠端機器上執行的 Jupyter socket 的代理。

如果我們從 Colab 介面的左窗格開啟 Files 窗格(預設顯示 /content 目錄),就會發現另一個有趣的請求:

這次 JSON 列舉遠端主機上的檔案做出了響應。這個URL(/tun/m//api/contents/)似乎指向提供檔案元資料的服務。

雙擊 Files 窗格里的檔案,Colab 就會開始下載檔案並且展示檔案詳細資訊。如果單擊\ /content/sample_data/README.md,則會對 /tun/m//files/ 發出請求,返回該檔案的內容。

很明顯,\ http://colab.research.google.com/tun/m// 是執行 Colab 例項伺服器的反向代理,它提供了 /socket.io 、 /files 和 /api/contents 端點。

讓我們看看是否有任何服務在 Colab 容器例項內執行。Colab 中內建有 lsof 程式,執行 lsof -iTCP -sTCP:LISTEN,列出所有在 TCP 埠上監聽網路請求的程序。

看!colab-fileshim、node 和 jupyter-notebook 看起來都值得一探究竟。由於我們已經使用過Files窗格,所以先看看 colab-fileshim,它有 PID 28,因此檢查 /proc 檔案系統,檢視程序的完整命令列:

接下來研究 /usr/local/bin/colab-fileshim.py。諷刺的是,我們其實可以直接在 Files 窗格做到這一點。這個程式更像是一個無趣的檔案伺服器,除了伺服器本身可以響應 localhost:3453/files (帶有檔案內容)和 localhost:3453/api/contents (帶有 JSON 元資料)。這意味著 Colab 會將這些請求從通道 URL 轉發到例項本身的埠3453。

在谷歌開發者工具的網路選項中,我們可以右鍵單擊,複製 cURL 命令來重現它。例如,這是用於檢視 README.md 檔案的 cURL 命令:

如果在本地計算機終端上執行此命令,會將該 README 檔案的內容列印到我們的終端,通過不斷嘗試和糾錯,我們可以減少大部分標頭,只留下如下內容:

x-colab-tunnel 標頭表面上是為了防止 XSS 攻擊,實際上是為了防止我們或黑客從常規瀏覽器選項發出這些請求。

cookie 標頭用於向 Google 提供身份驗證,證明我們可以訪問筆記本例項。由於 cookie 比較長且難以處理,在本文的其餘部分我們將其儲存到 shell 變數 $COLAB_COOKIE 中。

2

勝利1:揭示我們的伺服器

現在,我們已經發現了 Colab 的反向代理,看看是否可以用它為傳輸我們自己的請求。

我們可以簡單地用自己的伺服器替換程序,而不會影響現有的 colab-fileshim.py 伺服器!執行 pkill -f colab-fileshim 來終止現有伺服器,這樣就可以在同一個埠上啟動我們自己的伺服器。

下面做一個簡短的演示,我們將啟動 Python 預設的 HTTP 伺服器,然後在 localhost:3453/files 中提供我們自己的檔案。

瞧!我們現在可以更改 cURL 命令來下載我們自己的檔案!

注意 Colab 單元中的日誌行,可以證明我們的伺服器處理了請求:

遺憾的是,由於需要 x-colab-tunnel: Google 標頭,所以我們無法從瀏覽器直接訪問伺服器。

3

進一步研究

繼續進行研究,這次看一下之前發現的另一個有趣的東西,node。如果我們檢查 /proc/7/cmdline,會看到程序正在執行 /datalab/web/app.js。

一旦我們跳轉並閱讀該程式碼,會發現 /datalab/web 包含一個相當標準的NodeJS應用程式。除了之前看到的 /socketio/ 路由,它還公開了 /_proxy/{port}/ 路由。這應該讓我們可以從 Colab 例項上的任何埠訪問任何 URL!

啟動一個快速伺服器並測試一下。

可惜我們並不能從瀏覽器選項中檢視這個 HTML 頁面,Colab 拒絕代理任何請求,除非設定了 x-colab-tunnel: Google 標頭,如果我們嘗試從瀏覽器訪問這些URL,會看到一個 HTTP 400 客戶端錯誤頁面:

4

勝利2:揭示整個網頁

幸運的是,我們可以使用谷歌瀏覽器擴充套件程式將 HTTP 標頭即時插入瀏覽器請求中。我們將其設定為在所有請求上傳送 x-colab-tunnel: Google 標頭:

然後我們可以在瀏覽器中啟動通道 URL!

5

前往Jupyter Notebook

最後,讓我們看看第三個,也是最後一個有趣的程序,jupyter-notebook,它監聽埠 9000。

我們可以通過訪問 /tun/m//_proxy/9000 來使用之前的代理和標頭,嘗試從瀏覽器直接訪問埠。遺憾的是,出現了 HTTP 500 伺服器錯誤頁面,而不是 Jupyter 使用者介面。

奇怪的是,當我們從 Colab notebook 本身執行 !curl -i localhost:9000 來診斷這個問題時,仍然報錯了:

之前 lsof 的輸出為我們提供了一個線索:Jupyter 只監聽提供給 Colab 例項的私有 IP,而不是監聽 0.0.0.0/:: (所有介面上的所有 IP),這大概是為了避免將 Jupyter 介面暴露給我們。

谷歌並沒有盡全力隱藏介面,因此有一個快速修復的方法。

為了繞過監聽地址的限制,我們需要建立一個程序來監聽所有介面和 IP,並將它獲得的所有流量轉發到 Jupyter 正在監聽的特定 IP 地址。我們可以安裝socket代理工具 socat(Socket Cat) 來做到這一點。使用 socat 將流量在 localhost:9000 和 $HOSTNAME:9000 之間來回轉發:

這是一個開始!如果我們在瀏覽器中重新載入 URL,我們會看到部分 Jupyter 使用者介面,但顯然出現了問題。

這是因為 Jupyter 設定在域的根目錄下訪問(URL路徑 /),但我們的 Colab 通道的路徑是 /tun/m//_proxy/9000,這會弄亂 CSS 和 JS 檔案等資源的絕對路徑。

目前還沒有簡單的解決方案,我們需要一個完整的(子)域來將流量轉發到Jupyter伺服器。

6

勝利3:顯示Jupyter使用者介面

萬幸,Colab 有一個隱蔽的埠轉發的官方解決方案,它提供了一個完整的子域!它隱藏得非常好,發現它比發現內部反向代理花費了更長的時間!

如何使用 Colab 的官方埠轉發流量?從左側邊欄中開啟 Code Snippets 選項,然後找到 Output Handling 程式碼段。

單擊“檢視Source Notebook”,將會看到advanced_outputs.ipynb,這是Colab 高階使用者片段,展示了該平臺鮮為人知的功能。我們需要的特定片段可以在“瀏覽核心上執行的伺服器”標題下找到。

我們可以使用此程式碼段將 Jupyter 使用者介面公開為子域。

現在,我們可以單擊該連結(將 /tree 附加到 URL 來穩住 Jupyter),然後就可以檢視功能齊全的 Jupyter UI!

終於,幾乎完成了所有工作。谷歌似乎已將官方代理限制為僅GET請求,只允許我們檢視但不能執行Notebooks。

7

結語

恭喜你看到了最後,希望這對展示你不瞭解的Colab相關工作原理以及學習逆向工程工具的半結構化方法會有價值。也希望能激發你更深入地瞭解自己每天使用的工具和產品的內部結構!

(本文經授權後編譯釋出。原文:\ http://dagshub.com/blog/reverse-engineering-google-colab/ )

頭圖源自wir_sind_klein, Pixabay

\ 歡迎下載體驗 OneFlow v0.8.0 最新版本: http://github.com/Oneflow-Inc/oneflow/