Node.js v18.18.2 文档


目录

权限#

权限可用于控制 Node.js 进程可以访问哪些系统资源,或者进程可以对这些资源执行哪些操作。权限还可以控制哪些模块可以被其他模块访问。

  • 基于模块的权限控制应用程序执行期间其他模块可以使用哪些文件或 URL。例如,这可用于控制第三方依赖项可以访问哪些模块。

如果您发现潜在的安全漏洞,请参阅我们的 安全策略

基于模块的权限#

策略#

稳定性:1 - 实验性

Node.js 包含对创建加载代码策略的实验性支持。

策略是一项安全功能,旨在保证 Node.js 能够加载哪些代码。策略的使用假定策略文件的安全实践,例如通过使用文件权限确保策略文件不会被 Node.js 应用程序覆盖。

最佳实践是确保策略清单对于正在运行的 Node.js 应用程序是只读的,并且该文件不能被正在运行的 Node.js 应用程序以任何方式更改。一种典型的设置是将策略文件创建为与运行 Node.js 的用户 ID 不同的用户 ID,并向运行 Node.js 的用户 ID 授予读取权限。

启用#

--experimental-policy标志可用于在加载模块时启用策略功能。

设置后,所有模块都必须符合传递给该标志的策略清单文件:

node --experimental-policy=policy.json app.js 

策略清单将用于对 Node.js 加载的代码实施约束。

为了减少对磁盘上策略文件的篡改,可以通过--policy-integrity提供策略文件本身的完整性。这允许运行node并断言策略文件内容,即使磁盘上的文件发生更改也是如此。

node --experimental-policy=policy.json --policy-integrity="sha384-SggXRQHwCG8g+DktYYzxkXRIkTiEYWBHqev0xnpCxYlqMBufKZHAHQM3/boDaI/0" app.js 
特征#
错误行为#

当策略检查失败时,Node.js 默认会抛出错误。通过在策略清单中定义“onerror”字段,可以将错误行为更改为几种可能性之一。以下值可用于更改行为:

  • "exit":将立即退出该过程。不允许运行任何清理代码。
  • "log":将在失败的站点记录错误。
  • "throw":将在失败的位置抛出 JS 错误。这是默认设置。
{
  "onerror": "log",
  "resources": {
    "./app/checked.js": {
      "integrity": "sha384-SggXRQHwCG8g+DktYYzxkXRIkTiEYWBHqev0xnpCxYlqMBufKZHAHQM3/boDaI/0"
    }
  }
} 
完整性检查#

策略文件必须使用子资源完整性字符串的完整性检查,该字符串与与绝对 URL 关联的浏览器 完整性属性兼容 。

使用require()import时,如果已指定策略清单,则会检查加载中涉及的所有资源的完整性。如果资源与清单中列出的完整性不匹配,则会抛出错误。

允许加载文件checked.js的策略文件示例:

{
  "resources": {
    "./app/checked.js": {
      "integrity": "sha384-SggXRQHwCG8g+DktYYzxkXRIkTiEYWBHqev0xnpCxYlqMBufKZHAHQM3/boDaI/0"
    }
  }
} 

策略清单中列出的每个资源可以采用以下格式之一来确定其位置:

  1. 清单中资源的相对 URL 字符串,例如./resource.js../resource.js/resource.js
  2. 资源的完整 URL 字符串,例如file:///resource.js

加载资源时,整个 URL 必须匹配,包括搜索参数和哈希片段。尝试加载./a.js时不会使用 ./a.js?b ,反之亦然。

要生成完整性字符串,可以使用node -e 'process.stdout.write("sha256-");process.stdin.pipe(crypto.createHash("sha256").setEncoding("base64")).pipe(process.stdout)' < FILE等脚本 。

完整性可以指定为布尔值true,以接受对本地开发有用的资源的任何主体。不建议在生产中使用它,因为它会导致资源的意外更改被视为有效。

依赖重定向#

应用程序可能需要发布模块的修补版本或阻止模块允许所有模块访问所有其他模块。可以通过拦截加载希望被替换的模块的尝试来使用重定向。

{
  "resources": {
    "./app/checked.js": {
      "dependencies": {
        "fs": true,
        "os": "./app/node_modules/alt-os",
        "http": { "import": true }
      }
    }
  }
} 

依赖项由请求的说明符字符串作为键控,其值为truenull、指向要解析的模块的字符串或条件对象。

说明符字符串不执行任何搜索,并且必须与提供给require()import的内容完全匹配,规范化步骤除外。因此,如果策略使用多个不同的字符串指向同一模块(例如排除扩展名),则策略中可能需要多个说明符。

说明符字符串已规范化,但在用于匹配之前不会解析,以便与导入映射具有一定的兼容性,例如,如果资源file:///C:/app/server.js从位于file:///C:/app/policy.json的策略获得以下重定向:

{
  "resources": {
    "file:///C:/app/utils.js": {
      "dependencies": {
        "./utils.js": "./utils-v2.js"
      }
    }
  }
} 

然后,用于加载file:///C:/app/utils.js 的任何说明符都将被拦截并重定向到file:///C:/app/utils-v2.js,而不是使用绝对或相对说明符。但是,如果使用的说明符不是绝对或相对 URL 字符串,则不会被拦截。因此,如果使用诸如import('#utils')之类的导入,则不会被拦截。

如果重定向的值为true,则将使用策略文件顶部的“依赖项”字段。如果策略文件顶部的字段是 true,则使用默认节点搜索算法来查找模块。

如果重定向的值是字符串,则会相对于清单进行解析,然后立即使用而无需搜索。

根据策略,尝试解析且未在依赖项中列出的任何说明符字符串都会导致错误。

重定向不会阻止通过直接访问require.cache或通过允许访问加载模块的module.constructor 等方式访问 API。策略重定向仅影响require()import的说明符。需要采取其他方法(例如防止通过变量对 API 进行不需要的访问)来锁定加载模块的路径。

可以指定依赖关系映射的布尔值true以允许模块加载任何说明符而无需重定向。这对于本地开发很有用,并且可能在生产中具有一些有效的用途,但只有在审核模块以确保其行为有效后才应谨慎使用。

package.json中的"exports"类似,依赖项也可以指定为包含分支依赖项加载方式的条件的对象。在前面的示例中,当"import"条件是加载的一部分时,允许 "http"

解析值的值为null会导致解析失败。这可用于确保明确阻止某些类型的动态访问。

已解析模块位置的未知值会导致失败,但不保证向前兼容。

示例:修补依赖项#

重定向的依赖项可以提供适合应用程序的减弱或修改的功能。例如,通过包装原始数据来记录有关函数持续时间计时的数据:

const original = require('fn');
module.exports = function fn(...args) {
  console.time();
  try {
    return new.target ?
      Reflect.construct(original, args) :
      Reflect.apply(original, this, args);
  } finally {
    console.timeEnd();
  }
}; 
范围#

使用清单的"scopes"字段一次设置多个资源的配置。"scopes"字段的工作原理是按资源段匹配资源。如果范围或资源包含"cascade": true,则将在其包含范围中搜索未知说明符。级联的包含范围是通过删除 特殊方案的段、保留尾随"/"后缀以及删除查询和哈希片段来递归地减少资源 URL 来找到的。这会导致 URL 最终还原到其原始位置。如果 URL 不特殊,则范围将由 URL 的来源定位。如果没有找到源的范围或者源不透明的情况,则可以使用协议字符串作为范围。如果找不到 URL 协议的范围,则将使用最终的空字符串""范围。

请注意,blob: URL 采用其包含的路径的来源,因此"blob:https://nodejs.org"的范围将无效,因为任何 URL 都不能具有blob:https://nodejs.org的来源; 以 blob:https://nodejs.org/开头的 URL将使用https://nodejs.org作为其来源,并因此使用https:作为其协议范围。对于不透明的来源blob: URL,它们的协议范围将是blob:,因为它们不采用来源。

例子#
{
  "scopes": {
    "file:///C:/app/": {},
    "file:": {},
    "": {}
  }
} 

给定位于file:///C:/app/bin/main.js的文件,将按顺序检查以下范围:

  1. "file:///C:/app/bin/"

这确定了"file:///C:/app/bin/"中所有基于文件的资源的策略 。这不在策略的"scopes"字段中,因此将被跳过。将此范围添加到策略中会导致它在"file:///C:/app/"范围之前使用。

  1. "file:///C:/app/"

这确定了"file:///C:/app/"中所有基于文件的资源的策略 。它位于策略的"scopes"字段中,它将确定file:///C:/app/bin/main.js处资源的策略。如果范围具有"cascade": true ,则任何有关资源的未满足的查询都将委托给file:///C:/app/bin/main.js"file:"的下一个相关范围。

  1. "file:///C:/"

这确定了"file:///C:/"中所有基于文件的资源的策略。这不在策略的"scopes"字段中,因此将被跳过。除非"file:///"设置为级联或不在策略的"scopes"中,否则它不会用于 file:///C:/app/bin/main.js

  1. "file:///"

这确定了localhost上所有基于文件的资源的策略。这不在策略的"scopes"字段中,因此将被跳过。除非"file:///"设置为级联或不在策略的"scopes"中,否则它不会用于 file:///C:/app/bin/main.js

  1. "file:"

这确定了所有基于文件的资源的策略。除非"file:///"设置为级联或不在策略的"scopes"中,否则它不会用于 file:///C:/app/bin/main.js

  1. ""

这决定了所有资源的策略。除非将"file:"设置为级联,否则它不会用于 file:///C:/app/bin/main.js

完整性使用范围#

在范围上将完整性设置为true会将清单中未找到的任何资源的完整性设置为true

在范围上将完整性设置为null会将清单中未找到的任何资源的完整性设置为匹配失败。

不包含完整性与将完整性设置为null相同。

如果显式设置了"integrity",则完整性检查的"cascade"将被忽略。

以下示例允许加载任何文件:

{
  "scopes": {
    "file:": {
      "integrity": true
    }
  }
} 
使用范围的依赖关系重定向#

以下示例将允许访问fs以获取./app/中的所有资源 :

{
  "resources": {
    "./app/checked.js": {
      "cascade": true,
      "integrity": true
    }
  },
  "scopes": {
    "./app/": {
      "dependencies": {
        "fs": true
      }
    }
  }
} 

以下示例将允许所有data:资源访问 fs

{
  "resources": {
    "data:text/javascript,import('node:fs');": {
      "cascade": true,
      "integrity": true
    }
  },
  "scopes": {
    "data:": {
      "dependencies": {
        "fs": true
      }
    }
  }
} 
示例:import map模拟#

给定一个导入映射:

{
  "imports": {
    "react": "./app/node_modules/react/index.js"
  },
  "scopes": {
    "./ssr/": {
      "react": "./app/node_modules/server-side-react/index.js"
    }
  }
} 
{
  "dependencies": true,
  "scopes": {
    "": {
      "cascade": true,
      "dependencies": {
        "react": "./app/node_modules/react/index.js"
      }
    },
    "./ssr/": {
      "cascade": true,
      "dependencies": {
        "react": "./app/node_modules/server-side-react/index.js"
      }
    }
  }
} 

import map假设您默认可以获得任何资源。这意味着 策略顶层的"dependencies"应设置为true。策略要求选择加入,因为它启用应用程序交叉链接的所有资源,这对于许多场景来说没有意义。他们还假设任何给定范围都可以访问其允许的依赖项之上的任何范围;所有模拟导入映射的作用域都必须设置"cascade": true

导入映射的“导入”只有一个顶级范围。因此,要模拟"imports",请使用""范围。为了模拟"scopes",请使用 "scopes",其方式与"scopes"在导入映射中的工作方式类似。

注意事项:策略不使用字符串匹配来进行各种范围查找。他们进行 URL 遍历。这意味着blob:data: URL 之类的内容可能无法在两个系统之间完全互操作。例如,导入映射可以通过按 / 字符对 URL 进行分区来部分匹配data:blob: URL ,但策略故意不能这样做。对于blob: URL 导入映射范围不采用blob: URL的来源。

此外,导入映射仅适用于import,因此可能需要 向所有依赖项映射添加"import"条件。

NodeJS中文文档为Read dev Docs平台提供托管,中文NodeJS文档均由英文版NodeJS文档翻译,版权属于nodejs.org