逆向工程:揭示Google Colab未公開的秘密
來源|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)網是什么
交換機相關文章:交換機工作原理