权限#

权限可用于控制 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/*

配置文件支持#

除了在命令行传递权限标志外,在使用实验性 [--experimental-config-file][] 标志时,也可以在 Node.js 配置文件中声明这些权限。权限选项必须放置在顶层 permission 对象内。

示例 node.config.json

{
  "permission": {
    "allow-fs-read": ["./foo"],
    "allow-fs-write": ["./bar"],
    "allow-child-process": true,
    "allow-worker": true,
    "allow-net": true,
    "allow-addons": false
  }
}

当配置文件中存在 permission 命名空间时,Node.js 会自动启用 --permission 标志。运行方式:

$ node --experimental-default-config-file app.js
将权限模型与 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 时根据需要配置权限变得很容易。

权限模型限制#

在使用此系统之前,您需要了解一些限制

  • 该模型不会继承给工作线程。
  • 使用权限模型时,以下功能将受到限制
    • 原生模块
    • 网络
    • 子进程 (Child process)
    • 工作线程
    • 检查器协议
    • 文件系统访问
    • WASI
  • 权限模型在 Node.js 环境设置完成后初始化。但是,某些标志(如 --env-file--openssl-config)旨在在环境初始化之前读取文件。因此,此类标志不受权限模型规则的约束。这也适用于可以通过 v8.setFlagsFromString 在运行时设置的 V8 标志。
  • 启用权限模型后,无法在运行时请求 OpenSSL 引擎,这会影响内置的 crypto、https 和 tls 模块。
  • 启用权限模型后,无法加载运行时可加载扩展,这会影响 sqlite 模块。
  • 通过 node:fs 模块使用现有的文件描述符会绕过权限模型。
局限性与已知问题#
  • 即使目标位置在已授予访问权限的路径集合之外,符号链接也会被追踪。相对符号链接可能会允许访问任意文件和目录。在启用权限模型启动应用程序时,必须确保已授予访问权限的路径中不包含相对符号链接。