許可權#

許可權可用於控制 Node.js 程序可以訪問哪些系統資源,或程序可以對這些資源執行哪些操作。

  • 基於程序的許可權控制 Node.js 程序對資源的訪問。資源可以被完全允許或拒絕,或者可以控制與其相關的操作。例如,可以允許檔案系統讀取,同時拒絕寫入。此功能不能防止惡意程式碼。根據 Node.js 的安全策略,Node.js 信任其被要求執行的任何程式碼。

許可權模型實現了一種“安全帶”方法,它能防止受信任的程式碼意外更改檔案或使用未明確授予訪問許可權的資源。在存在惡意程式碼的情況下,它不提供安全保證。惡意程式碼可以繞過許可權模型,並在不受許可權模型施加的限制下執行任意程式碼。

如果您發現潛在的安全漏洞,請參閱我們的安全策略

基於程序的許可權#

許可權模型#

穩定性:2 - 穩定

Node.js 許可權模型是一種在執行期間限制對特定資源訪問的機制。該 API 存在於一個標誌 --permission 之後,啟用該標誌後,將限制對所有可用許可權的訪問。

可用的許可權由 --permission 標誌記錄。

當使用 --permission 啟動 Node.js 時,透過 fs 模組訪問檔案系統、訪問網路、衍生程序、使用 node:worker_threads、使用原生外掛、使用 WASI 以及啟用執行時檢查器的能力都將受到限制(SIGUSR1 的監聽器將不會被建立)。

$ node --permission index.js

Error: Access to this API has been restricted
    at node:internal/main/run_main_module:23:47 {
  code: 'ERR_ACCESS_DENIED',
  permission: 'FileSystemRead',
  resource: '/home/user/index.js'
} 

允許訪問衍生程序和建立工作執行緒可以透過分別使用 --allow-child-process--allow-worker 來實現。

要允許網路訪問,請使用 --allow-net;在使用許可權模型時要允許原生外掛,請使用 --allow-addons 標誌。對於 WASI,請使用 --allow-wasi 標誌。

執行時 API#

當透過 --permission 標誌啟用許可權模型時,process 物件會新增一個 permission 屬性。此屬性包含一個函式:

permission.has(scope[, reference])#

用於在執行時檢查許可權的 API 呼叫 (permission.has())

process.permission.has('fs.write'); // true
process.permission.has('fs.write', '/home/rafaelgss/protected-folder'); // true

process.permission.has('fs.read'); // true
process.permission.has('fs.read', '/home/rafaelgss/protected-folder'); // false 
檔案系統許可權#

許可權模型預設會限制透過 node:fs 模組對檔案系統的訪問。它不保證使用者無法透過其他方式訪問檔案系統,例如透過 node:sqlite 模組。

要允許訪問檔案系統,請使用 --allow-fs-read--allow-fs-write 標誌。

$ node --permission --allow-fs-read=* --allow-fs-write=* index.js
Hello world! 

預設情況下,應用程式的入口點會被包含在允許的檔案系統讀取列表中。例如:

$ node --permission index.js 
  • index.js 將被包含在允許的檔案系統讀取列表中。
$ node -r /path/to/custom-require.js --permission index.js. 
  • /path/to/custom-require.js 將被包含在允許的檔案系統讀取列表中。
  • index.js 將被包含在允許的檔案系統讀取列表中。

這兩個標誌的有效引數是:

  • * - 分別允許所有 FileSystemReadFileSystemWrite 操作。
  • 相對於當前工作目錄的路徑。
  • 絕對路徑。

示例

  • --allow-fs-read=* - 將允許所有 FileSystemRead 操作。
  • --allow-fs-write=* - 將允許所有 FileSystemWrite 操作。
  • --allow-fs-write=/tmp/ - 將允許對 /tmp/ 資料夾的 FileSystemWrite 訪問。
  • --allow-fs-read=/tmp/ --allow-fs-read=/home/.gitignore - 允許對 /tmp/ 資料夾 /home/.gitignore 路徑的 FileSystemRead 訪問。

同樣支援萬用字元:

  • --allow-fs-read=/home/test* 將允許對所有匹配萬用字元的內容進行讀取訪問。例如:/home/test/file1/home/test2

在傳遞萬用字元(*)之後,所有後續字元都將被忽略。例如:/home/*.js 的作用將類似於 /home/*

當權限模型初始化時,如果指定的目錄存在,它將自動新增一個萬用字元 (*)。例如,如果 /home/test/files 存在,它將被視為 /home/test/files/*。但是,如果目錄不存在,則不會新增萬用字元,訪問許可權將僅限於 /home/test/files。如果你想允許訪問一個尚不存在的資料夾,請務必明確包含萬用字元:/my-path/folder-do-not-exist/*

配合 npx 使用許可權模型#

如果你使用 npx 來執行 Node.js 指令碼,你可以透過傳遞 --node-options 標誌來啟用許可權模型。例如:

npx --node-options="--permission" package-name 

這會為所有由 npx 衍生的 Node.js 程序設定 NODE_OPTIONS 環境變數,而不會影響 npx 程序本身。

使用 npx 時的 FileSystemRead 錯誤

上述命令很可能會丟擲一個 FileSystemRead 無效訪問錯誤,因為 Node.js 需要檔案系統讀取許可權來定位和執行包。為了避免這種情況:

  1. 使用全域性安裝的包 透過執行以下命令授予對全域性 node_modules 目錄的讀取許可權:

    npx --node-options="--permission --allow-fs-read=$(npm prefix -g)" package-name 
  2. 使用 npx 快取 如果你是臨時安裝包或依賴 npx 快取,請授予對 npm 快取目錄的讀取許可權:

    npx --node-options="--permission --allow-fs-read=$(npm config get cache)" package-name 

你通常傳遞給 node 的任何引數(例如,--allow-* 標誌)也可以透過 --node-options 標誌傳遞。這種靈活性使得在使用 npx 時可以輕鬆地按需配置許可權。

許可權模型約束#

在使用此係統之前,你需要了解一些約束:

  • 該模型不會繼承到工作執行緒(worker thread)。
  • 當使用許可權模型時,以下功能將受到限制:
    • 原生模組
    • 網路
    • 子程序 (Child process)
    • 工作執行緒
    • 檢查器協議
    • 檔案系統訪問
    • WASI
  • 許可權模型在 Node.js 環境設定之後初始化。然而,某些標誌如 --env-file--openssl-config 被設計為在環境初始化之前讀取檔案。因此,這些標誌不受許可權模型規則的約束。同樣的情況也適用於可以透過 v8.setFlagsFromString 在執行時設定的 V8 標誌。
  • 當啟用許可權模型時,不能在執行時請求 OpenSSL 引擎,這會影響內建的 crypto、https 和 tls 模組。
  • 當啟用許可權模型時,無法載入執行時可載入擴充套件,這會影響 sqlite 模組。
  • 透過 node:fs 模組使用現有檔案描述符會繞過許可權模型。
限制和已知問題#
  • 符號連結將被跟蹤,即使它們指向了已授予訪問許可權的路徑集合之外的位置。相對符號連結可能允許訪問任意檔案和目錄。在使用許可權模型啟用應用程式時,你必須確保所有已授予訪問許可權的路徑都不包含相對符號連結。