博客專欄

EEPW首頁 > 博客 > 逆向工程:揭示Google Colab未公開的秘密

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

發(fā)布人:AI科技大本營 時間:2022-09-17 來源:工程師 發(fā)布文章

來源|Open Source Data Science Tools

翻譯|程浩源


Google Colaboratory,簡稱 “Colab” ,是一個免費的Jupyter notebook云平臺。Colab 不僅可以為用戶提供 Python 和 R notebooks 的運行環(huán)境,而且還允許用戶免費共享部分 GPU 和 TPU 資源。

 

對于負責在 Jupyter Notebook 編程的數(shù)據(jù)科學家來說,Colab早已成為了默認的運行環(huán)境。然而,將 Colab 的算力運用到除 Jupter Notebooks 以外的其他應用,則是一件極其困難的事。

 

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

 

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

 

出于這個原因,今天我們將探究 Google Colab 的內部結構,并嘗試稍微改變 Colab 的內置規(guī)則。需要提前聲明的是,我們只是想探究 Colab,不會對 Colab 本身或者它的用戶造成任何影響。

 

圖片

揭開幕后的秘密

 

Colab 的秘密在于它的后端:谷歌服務器為 Colab 提供基礎設施支持,讓用戶可以輕松運行代碼。因此,我們第一步先分析 Colab 的 API,最簡單的方法是檢查 Colab 在正常運行期間進行的 API 調用。

 

首先打開谷歌開發(fā)者工具,找到網絡(Network)選項,然后運行一段代碼,開發(fā)者工具開始記錄 Colab 發(fā)出的每個請求,然后我們發(fā)現(xiàn)了一些有趣的東西。


圖片

圖片

 

看上去這個URL(/tun/m/<id>/socket.io)是遠程機器上運行的 Jupyter socket 的代理。


如果我們從 Colab 界面的左窗格打開 Files 窗格(默認顯示 /content 目錄),就會發(fā)現(xiàn)另一個有趣的請求:

 

圖片

圖片

 

這次 JSON 枚舉遠程主機上的文件做出了響應。這個URL(/tun/m/<id>/api/contents/)似乎指向提供文件元數(shù)據(jù)的服務。


圖片

 

雙擊 Files 窗格里的文件,Colab 就會開始下載文件并且展示文件詳細信息。如果單擊 /content/sample_data/README.md,則會對 /tun/m/<id>/files/ 發(fā)出請求,返回該文件的內容。

 

圖片

 

很明顯,https://colab.research.google.com/tun/m/<id>/ 是運行 Colab 實例服務器的反向代理,它提供了 /socket.io 、 /files 和 /api/contents 端點。

 

讓我們看看是否有任何服務在 Colab 容器實例內運行。Colab 中內置有 lsof 程序,運行 lsof -iTCP -sTCP:LISTEN,列出所有在 TCP 端口上監(jiān)聽網絡請求的進程。


圖片

 

看!colab-fileshim、node 和 jupyter-notebook 看起來都值得一探究竟。由于我們已經使用過Files窗格,所以先看看 colab-fileshim,它有 PID 28,因此檢查 /proc 文件系統(tǒng),查看進程的完整命令行:

 

圖片


接下來研究 /usr/local/bin/colab-fileshim.py。諷刺的是,我們其實可以直接在 Files 窗格做到這一點。這個程序更像是一個無趣的文件服務器,除了服務器本身可以響應 localhost:3453/files (帶有文件內容)和 localhost:3453/api/contents (帶有 JSON 元數(shù)據(jù))。這意味著 Colab 會將這些請求從信道 URL 轉發(fā)到實例本身的端口3453。


在谷歌開發(fā)者工具的網絡選項中,我們可以右鍵單擊,復制 cURL 命令來重現(xiàn)它。例如,這是用于查看 README.md 文件的 cURL 命令:

 

圖片


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

 

圖片

 

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


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

 

圖片

 

圖片

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

 

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

 

我們可以簡單地用自己的服務器替換進程,而不會影響現(xiàn)有的 colab-fileshim.py 服務器!運行 pkill -f colab-fileshim 來終止現(xiàn)有服務器,這樣就可以在同一個端口上啟動我們自己的服務器。

 

下面做一個簡短的演示,我們將啟動 Python 默認的 HTTP 服務器,然后在 localhost:3453/files 中提供我們自己的文件。

 

圖片

 

瞧!我們現(xiàn)在可以更改 cURL 命令來下載我們自己的文件!


圖片

圖片

 

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


圖片

 

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


圖片

進一步研究 

 

繼續(xù)進行研究,這次看一下之前發(fā)現(xiàn)的另一個有趣的東西,node。如果我們檢查 /proc/7/cmdline,會看到進程正在運行 /datalab/web/app.js。


一旦我們跳轉并閱讀該代碼,會發(fā)現(xiàn) /datalab/web 包含一個相當標準的NodeJS應用程序。除了之前看到的 /socketio/ 路由,它還公開了 /_proxy/{port}/ 路由。這應該讓我們可以從 Colab 實例上的任何端口訪問任何 URL!

 

啟動一個快速服務器并測試一下。


圖片

圖片

 

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

 

圖片

 

 

圖片

勝利2:揭示整個網頁

 

幸運的是,我們可以使用谷歌瀏覽器擴展程序將 HTTP 標頭即時插入瀏覽器請求中。我們將其設置為在所有請求上發(fā)送 x-colab-tunnel: Google 標頭:


圖片

 

然后我們可以在瀏覽器中啟動信道 URL!


圖片


圖片

前往Jupyter Notebook

 

最后,讓我們看看第三個,也是最后一個有趣的進程,jupyter-notebook,它監(jiān)聽端口 9000。

 

我們可以通過訪問 /tun/m/<id>/_proxy/9000 來使用之前的代理和標頭,嘗試從瀏覽器直接訪問端口。遺憾的是,出現(xiàn)了 HTTP 500 服務器錯誤頁面,而不是 Jupyter 用戶界面。

 

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


圖片


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

 

谷歌并沒有盡全力隱藏接口,因此有一個快速修復的方法。

 

為了繞過監(jiān)聽地址的限制,我們需要創(chuàng)建一個進程來監(jiān)聽所有接口和 IP,并將它獲得的所有流量轉發(fā)到 Jupyter 正在監(jiān)聽的特定 IP 地址。我們可以安裝socket代理工具 socat(Socket Cat) 來做到這一點。使用 socat 將流量在 localhost:9000 和 $HOSTNAME:9000 之間來回轉發(fā):


圖片

 

這是一個開始!如果我們在瀏覽器中重新加載 URL,我們會看到部分 Jupyter 用戶界面,但顯然出現(xiàn)了問題。

 

圖片


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

 

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


圖片

勝利3:顯示Jupyter用戶界面

 

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

 

如何使用 Colab 的官方端口轉發(fā)流量?從左側邊欄中打開 Code Snippets 選項,然后找到 Output Handling 代碼段。

 

單擊“查看Source Notebook”,將會看到advanced_outputs.ipynb,這是Colab 高級用戶片段,展示了該平臺鮮為人知的功能。我們需要的特定片段可以在“瀏覽內核上執(zhí)行的服務器”標題下找到。

 

我們可以使用此代碼段將 Jupyter 用戶界面公開為子域。

 

圖片


現(xiàn)在,我們可以單擊該鏈接(將 /tree 附加到 URL 來穩(wěn)住 Jupyter),然后就可以查看功能齊全的 Jupyter UI!


圖片

 

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


圖片

結語

 

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


原文:

https://dagshub.com/blog/reverse-engineering-google-colab/

*博客內容為網友個人發(fā)布,僅代表博主個人觀點,如有侵權請聯(lián)系工作人員刪除。

物聯(lián)網相關文章:物聯(lián)網是什么


交換機相關文章:交換機工作原理




關鍵詞: AI

相關推薦

技術專區(qū)

關閉