具代表性的面試主題

後端面試:如何在 Node.js 服務中採用 Permission Model?

後端困難
Offer.cc 編輯團隊發佈 更新

題幹

團隊想用 Node.js Permission Model 限制檔案、網路與子程序存取。你會如何評估安全邊界,並在生產服務中漸進啟用?

題目背景

你維護一個執行於容器的 Node.js API,依賴數個第三方套件,需讀取設定、存取物件儲存並偶爾啟動影像處理子程序。安全團隊希望啟用 --permission,只授予必要的檔案、網路與子程序權限。請說明威脅模型、權限清單、相容性測試、監控與回退方案。

面試官考察點

  • 是否知道 Permission Model 是降低受信程式碼誤用的 seat belt,不是惡意程式碼沙箱。
  • 能否把檔案、網路、child process、worker、native addon 等能力拆成最小授權。
  • 是否識別符號連結、既有檔案描述元、初始化順序與子程序/worker 繼承限制。
  • 能否設計灰度、錯誤觀測與不影響業務的回退。

澄清問題

先列出執行時版本、入口腳本、依賴是否使用 native addon、是否需要 worker/FFI/WASI、存取哪些路徑與網域,以及子程序是否必須由應用程式啟動。確認容器與作業系統層已有的 seccomp、使用者身分和唯讀檔案系統策略,避免把 Node 層能力當成唯一防線。

30 秒回答

我會先把它當作受信程式碼的最小權限控制,而非防禦惡意依賴的完整沙箱。用生產依賴清單與執行時稽核產生 fs.readfs.write、network、child、worker 等授權,先在影子環境與 1% 流量啟用,記錄 ERR_ACCESS_DENIED 與延遲變化。對 native addon、符號連結和既有 fd 做專門測試,保留容器級隔離。若錯誤率或關鍵依賴受影響,移除啟動參數即可回退,並繼續修正權限清單。

分步推導

1. 定義安全邊界

Node 文件把 Permission Model 描述為限制程序存取資源的機制,並明確它不防惡意程式碼;Node 信任被要求執行的程式碼。它適合降低受信應用程式意外讀寫或啟動資源的風險,不能取代容器、OS 使用者、seccomp 或依賴供應鏈防護。

2. 建立權限清單

從預設拒絕開始,只為設定與靜態資源授予 --allow-fs-read,為暫存輸出授予窄路徑 --allow-fs-write,為物件儲存網域授予 --allow-net,僅在確有需要時啟用 --allow-child-process--allow-worker--allow-addons。把授權記錄成版本化設定並由程式碼負責人審查。

3. 驗證執行時行為

覆蓋啟動、健康檢查、上傳、影像處理、排程工作與錯誤路徑。驗證 process.permission.has() 結果,並確認 permission.drop() 不可逆且只影響後續存取;已開啟的 fd、socket 或 worker 不會自動關閉。測試符號連結、native addon、npx 與子程序邊界。

4. 灰度與回退

先在 staging 與單個無狀態執行個體開啟,收集被拒權限的資源、呼叫堆疊、版本與租戶,避免記錄敏感內容。擴大前設定錯誤率、P95、啟動成功率與業務工作完成率閘門。回退只需撤銷 --permission 或對應 --allow-* 參數;同時保留容器唯讀、非 root 與網路策略。

高品質示範回答

我會先把服務依賴畫成權限矩陣:設定目錄唯讀、暫存目錄寫入、物件儲存必要網域、影像轉換的 child process,以及沒有業務理由就禁止 worker 與 native addon。Permission Model 預設限制 fs,透過 --allow-* 逐項放行;我會把參數放進版本化啟動設定,在 CI 用最小映像檔執行整合情境,確認每個路由與背景工作都能完成。灰度階段只覆蓋一類無狀態執行個體,按錯誤碼聚合 ERR_ACCESS_DENIED,並保留資源路徑雜湊而非原文。特別驗證符號連結、既有檔案描述元與子程序/worker 不繼承模型等限制;惡意程式碼風險繼續交給容器和 OS 隔離。達到啟動成功率、P95、拒絕事件與工作完成率門檻後再擴大。出現關鍵依賴拒絕或錯誤率上升時,撤銷啟動參數即可回到原行為,之後補齊權限清單再重試。

常見誤區

  • 宣稱 Permission Model 能安全執行惡意第三方套件。
  • 直接使用 --allow-fs-read=*--allow-fs-write=*,失去最小權限價值。
  • 忽略 native addon、worker、child process、WASI、FFI 與網路存取限制。
  • 認為 permission.drop() 會關閉已開啟的 fd、socket 或 worker。
  • 只在本機啟動測試,不覆蓋 npx、符號連結與真實背景工作。

追問與應對

如果問「它能取代容器沙箱嗎?」

回答:不能。Node 文件明確它不防惡意程式碼,應與非 root、唯讀檔案系統、seccomp、網路策略及依賴供應鏈控制疊加。

如果問「為什麼服務啟動後仍然讀不到檔案?」

回答:檢查入口腳本、設定路徑是否在允許清單,路徑萬用字元是否符合預期,以及初始化讀取是否發生在權限模型建立之後;用 permission.has() 與拒絕事件定位。

如果問「如何允許影像處理?」

回答:單獨授予 --allow-child-process,限制可執行檔與輸入輸出目錄,並讓子程序在容器與 OS 層繼續受限;若能改成純函式庫呼叫,優先移除子程序權限。

公開來源

同類題目