Spec-Zone.ru › Node.js 20 LTS

Разрешения

Разрешения могут использоваться для управления ресурсами системы, к которым имеет доступ процесс Node.js, или действиями, которые может выполнять процесс с этими ресурсами. Разрешения также могут контролировать доступ модулей друг к другу.

  • Разрешения на основе модулей контролируют доступ других модулей к файлам или URL-адресам во время выполнения приложения. Это можно использовать для контроля доступа сторонних зависимостей к модулям, например.

  • Разрешения на основе процесса контролируют доступ процесса Node.js к ресурсам. Ресурс может быть полностью разрешен или запрещен, или могут контролироваться действия, связанные с ним. Например, чтение из файловой системы может быть разрешено, а запись запрещена.

Если вы обнаружили потенциальную уязвимость безопасности, ознакомьтесь с нашей Политикой безопасности.

Модульные разрешения

Политики

Устойчивость: 0 - Устарело: Будет удалено в ближайшее время

Node.js содержит экспериментальную поддержку создания политик при загрузке кода.

Политики — это функция безопасности, предназначенная для обеспечения целостности загруженного кода.

Хотя она не работает как механизм происхождения для отслеживания источника кода, она служит надёжной защитой от выполнения вредоносного кода. В отличие от моделей, основанных на времени выполнения, которые могут ограничивать возможности после загрузки кода, политики Node.js сосредоточены на предотвращении загрузки вредоносного кода в приложение в первую очередь.

Использование политик предполагает безопасные методы для файлов политик, такие как обеспечение невозможности перезаписи файлов политик приложением Node.js с помощью прав доступа к файлам.

Лучшей практикой будет обеспечение того, что манифест политики является только для чтения для работающего приложения Node.js и что приложение Node.js во время выполнения не может изменить файл каким-либо образом. Типичная настройка заключается в создании файла политики с другим идентификатором пользователя, чем тот, под которым работает Node.js, и предоставлении прав чтения пользователю, под которым работает Node.js.

Включение

Флаг --experimental-policy может использоваться для включения функций политик при загрузке модулей.

После этого все модули должны соответствовать файлу манифеста политики, переданному в флаг:

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

Манифест политики будет использоваться для принудительного соблюдения ограничений на код, загружаемый Node.js.

Чтобы уменьшить возможность подмены файлов политик на диске, целостность файла политики может быть обеспечена с помощью --policy-integrity. Это позволяет запускать node и проверять содержимое файла политики даже в случае его изменения на диске.

node --experimental-policy=policy.json --policy-integrity="sha384-SggXRQHwCG8g+DktYYzxkXRIkTiEYWBHqev0xnpCxYlqMBufKZHAHQM3/boDaI/0" app.js copy
Функции
Поведение при ошибке

Если проверка политики завершается ошибкой, Node.js по умолчанию выбросит ошибку. Можно изменить поведение при ошибке на одно из нескольких возможных вариантов, определив поле "onerror" в манифесте политики. Доступны следующие значения для изменения поведения:

  • "exit": немедленно завершит процесс. Никакой код очистки запускаться не будет.
  • "log": запишет ошибку в месте возникновения.
  • "throw": выбросит ошибку JS в месте возникновения. Это значение по умолчанию.
{
  "onerror": "log",
  "resources": {
    "./app/checked.js": {
      "integrity": "sha384-SggXRQHwCG8g+DktYYzxkXRIkTiEYWBHqev0xnpCxYlqMBufKZHAHQM3/boDaI/0"
    }
  }
} copy
Проверки целостности

Файлы политик должны использовать проверки целостности с строками Subresource Integrity, совместимыми с атрибутом integrity браузера, связанным с абсолютными URL-адресами.

При использовании require() или import все ресурсы, участвующие в загрузке, проверяются на целостность, если указан манифест политики. Если ресурс не соответствует целостности, указанной в манифесте, будет выброшена ошибка.

Пример файла политики, который позволил бы загрузить файл checked.js:

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

Каждый ресурс, указанный в манифесте политики, может быть одного из следующих форматов для определения его местоположения:

  1. Строка относительного URL-адреса ресурса от манифеста, например ./resource.js, ../resource.js, или /resource.js.
  2. Полная строка URL-адреса ресурса, например file:///resource.js.

При загрузке ресурсов весь URL-адрес должен совпадать, включая параметры поиска и фрагмент. ./a.js?b не будет использоваться при попытке загрузить ./a.js и наоборот.

Для генерации строк целостности можно использовать скрипт, такой как 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 }
      }
    }
  }
} copy

Зависимости индексируются строкой запрошенного спецификатора и имеют значения true, null, строки, указывающей на модуль для разрешения, или объекта условий.

Строка спецификатора не выполняет поиск и должна точно совпадать с предоставленным в require() или import, за исключением этапа канонизации. Поэтому в политике может потребоваться несколько спецификаторов, если она использует несколько различных строк для указания одного и того же модуля (например, исключая расширение).

Строки спецификаторов канонизируются, но не разрешаются перед использованием для сопоставления, чтобы обеспечить некоторую совместимость с картами импорта, например, если ресурсу file:///C:/app/utils.js было дано следующее перенаправление из политики, расположенной по адресу file:///C:/app/policy.json:

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

Любой спецификатор, используемый для загрузки file:///C:/app/utils.js, затем перехватывается и перенаправляется на file:///C:/app/utils-v2.js независимо от использования абсолютного или относительного спецификатора. Однако если используется спецификатор, который не является строкой абсолютного или относительного URL-адреса, он не перехватывается. Таким образом, если использовался импорт, такой как import('#utils'), он не перехватывался.

Если значение перенаправления равно true, будет использоваться поле "dependencies" в верхней части файла политики. Если это поле в верхней части файла политики равно true, будут использоваться стандартные алгоритмы поиска Node для поиска модуля.

Если значение перенаправления является строкой, оно разрешается относительно манифеста и немедленно используется без поиска.

Любая строка спецификатора, для которой пытается выполниться разрешение, и которая не указана в зависимостях, приводит к ошибке в соответствии с политикой.

Для карты зависимостей можно указать логическое значение true для разрешения загрузки модулем любого спецификатора без перенаправления. Это может быть полезно для локальной разработки и может иметь некоторое практическое применение в производственной среде, но следует использовать с осторожностью после аудита модуля для проверки его поведения.

Аналогично "exports" в package.json, зависимости также можно указать как объекты, содержащие условия, которые разветвляют способ загрузки зависимостей. В приведенном выше примере "http" разрешен, когда условие "import" является частью его загрузки.

Значение 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();
  }
}; copy
Сферы

Используйте поле "scopes" манифеста для установки конфигурации для многих ресурсов одновременно. Поле "scopes" работает путём сопоставления ресурсов по их сегментам. Если область или ресурс включает "cascade": true, неизвестные спецификаторы будут искаться в их содержащей области. Содержащая область для каскадирования находится путём рекурсивного уменьшения URL-адреса ресурса путём удаления сегментов для специальных схем, сохраняя хвостовые "/" суффиксы и удаляя запрос и фрагмент. Это приводит к окончательному уменьшению URL-адреса до его источника. Если URL-адрес не специальный, область будет найдена по источнику URL-адреса. Если область не найдена для источника или в случае неявных источников, можно использовать строку протокола в качестве области. Если область не найдена для протокола URL-адреса, будет использоваться конечная пустая строка "" области.

Обратите внимание, что blob: URL-адреса принимают свой источник из пути, который они содержат, поэтому область "blob:https://nodejs.org" не повлияет, так как ни один URL-адрес не может иметь источник blob:https://nodejs.org; URL-адреса, начинающиеся с blob:https://nodejs.org/ будут использовать https://nodejs.org для своего источника, и, следовательно, https: для своей области протокола. Для URL-адресов blob: неявного источника у них будет blob: для области протокола, так как они не принимают источники.

Пример
{
  "scopes": {
    "file:///C:/app/": {},
    "file:": {},
    "": {}
  }
} copy

Учитывая файл, расположенный по адресу 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:///C:/app/bin/main.js если "file:///C:/app/" установлено на каскадное или отсутствует в "scopes" политики.

  1. "file:///"

Это определяет политику для всех файловых ресурсов на localhost. Это не в поле "scopes" политики и будет пропущено. Оно не будет использоваться для file:///C:/app/bin/main.js если "file:///C:/" установлено на каскадное или отсутствует в "scopes" политики.

  1. "file:"

Это определяет политику для всех файловых ресурсов. Оно не будет использоваться для file:///C:/app/bin/main.js если "file:///" установлено на каскадное или отсутствует в "scopes" политики.

  1. ""

Это определяет политику для всех ресурсов. Оно не будет использоваться для file:///C:/app/bin/main.js если "file:" установлено на каскадное.

Целостность при использовании областей

Установка целостности на true для области установит целостность любого ресурса, отсутствующего в манифесте, на true.

Установка целостности null в области установит целостность для любого ресурса, не найденного в манифесте, чтобы не соответствовать.

Отсутствие целостности равнозначно установке целостности в null.

"cascade" для проверок целостности будут проигнорированы, если "integrity" явно задан.

Следующий пример позволяет загружать любые файлы:

{
  "scopes": {
    "file:": {
      "integrity": true
    }
  }
} copy
Перенаправление зависимостей с использованием областей

Следующий пример позволит получить доступ к fs для всех ресурсов в ./app/:

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

Следующий пример позволит получить доступ к fs для всех data: ресурсов:

{
  "resources": {
    "data:text/javascript,import('node:fs');": {
      "cascade": true,
      "integrity": true
    }
  },
  "scopes": {
    "data:": {
      "dependencies": {
        "fs": true
      }
    }
  }
} copy
Пример: эмуляция import maps

Учитывая import map:

{
  "imports": {
    "react": "./app/node_modules/react/index.js"
  },
  "scopes": {
    "./ssr/": {
      "react": "./app/node_modules/server-side-react/index.js"
    }
  }
} copy
{
  "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"
      }
    }
  }
} copy

Import maps предполагают, что по умолчанию можно получить любой ресурс. Это означает, что "dependencies" на верхнем уровне политики должен быть установлен в true. Политики требуют, чтобы это было включено по умолчанию, так как это позволяет всей перекрестной связи ресурсов приложения, что не имеет смысла во многих сценариях. Они также предполагают, что любая заданная область имеет доступ к любой области над разрешенными зависимостями; все области, эмулирующие import maps, должны установить "cascade": true.

Import maps имеют только одну область верхнего уровня для своих «импортов». Таким образом, для эмуляции "imports" используйте область "". Для эмуляции "scopes" используйте область "scopes" аналогичным образом, как "scopes" работает в import maps.

Ограничения: политики не используют сопоставление строк для различных способов поиска области. Они выполняют обход по URL. Это означает, что такие вещи, как blob: и data: URL могут не быть полностью совместимы между двумя системами. Например, import maps могут частично сопоставить data: или blob: URL, разделив URL на символ /, политики намеренно не могут. Для blob: URL области import maps не принимают происхождение blob: URL.

Кроме того, import maps работают только с import, поэтому может быть целесообразно добавить условие "import" ко всем отображениям зависимостей.

Гарантии
  • Политики гарантируют целостность файла, когда модуль загружается с помощью require(), import() или new Module().
  • Перенаправление не препятствует доступу к API через такие средства, как прямой доступ к require.cache которые позволяют получить доступ к загруженным модулям. Перенаправление политики влияет только на указатели к require() и import.
  • Утверждение целостности модуля в модели угроз политик подразумевает, что они разрешены для вмешательства и даже обхода функций безопасности после загрузки, поэтому ожидается среда/временная закалка.

Разрешения, основанные на процессе

Модель разрешений

Стабильность: 1.1 - Активное развитие

Модель разрешений Node.js — это механизм для ограничения доступа к определенным ресурсам во время выполнения. API существует за флагом --experimental-permission, который при включении будет ограничивать доступ ко всем доступным разрешениям.

Доступные разрешения документированы флагом --experimental-permission.

При запуске Node.js с --experimental-permission, доступ к файловой системе через модуль fs, запуску процессов, использованию node:worker_threads, нативным дополнениям и включению инспектора среды выполнения будет ограничен.

$ node --experimental-permission index.js
node:internal/modules/cjs/loader:171
  const result = internalModuleStat(filename);
                 ^

Error: Access to this API has been restricted
    at stat (node:internal/modules/cjs/loader:171:18)
    at Module._findPath (node:internal/modules/cjs/loader:627:16)
    at resolveMainPath (node:internal/modules/run_main:19:25)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:76:24)
    at node:internal/main/run_main_module:23:47 {
  code: 'ERR_ACCESS_DENIED',
  permission: 'FileSystemRead',
  resource: '/home/user/index.js'
} copy

Разрешение доступа к запуску процесса и созданию потоков рабочих может быть выполнено с помощью --allow-child-process и --allow-worker соответственно.

Для разрешения нативных дополнений при использовании модели разрешений используйте флаг --allow-addons.

API среды выполнения

При включении модели разрешений через флаг --experimental-permission добавляется новое свойство permission к объекту process. Это свойство содержит одну функцию:

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 copy
Разрешения файловой системы

Для разрешения доступа к файловой системе используйте флаги --allow-fs-read и --allow-fs-write:

$ node --experimental-permission --allow-fs-read=* --allow-fs-write=* index.js
Hello world!
(node:19836) ExperimentalWarning: Permission is an experimental feature
(Use `node --trace-warnings ...` to show where the warning was created) copy

Допустимые аргументы для обоих флагов:

  • * - для разрешения всех FileSystemRead или FileSystemWrite операций соответственно.
  • Пути, разделенные запятыми (,) для разрешения только соответствующих FileSystemRead или FileSystemWrite операций соответственно.

Пример:

  • --allow-fs-read=* - разрешит все FileSystemRead операции.
  • --allow-fs-write=* - разрешит все FileSystemWrite операции.
  • --allow-fs-write=/tmp/ - разрешит FileSystemWrite доступ к папке /tmp/.
  • --allow-fs-read=/tmp/ --allow-fs-read=/home/.gitignore - разрешает FileSystemRead доступ к папке /tmp/ и пути /home/.gitignore.

Поддерживаются также шаблоны:

  • --allow-fs-read=/home/test* позволит читать все, что соответствует шаблону. Примеры: /home/test/file1 или /home/test2

После прохождения символа шаблона (*) все последующие символы игнорируются. Например: /home/*.js будет работать аналогично /home/*.

Ограничения модели разрешений

Перед использованием этой системы вам необходимо знать ограничения:

  • Модель не наследуется дочерним узлом процесса или потоком рабочего процесса.
  • При использовании модели разрешений будут ограничены следующие возможности:
    • Нативные модули
    • Процессы дочерних элементов
    • Потоки рабочих процессов
    • Протокол инспектора
    • Доступ к файловой системе
  • Модель разрешений инициализируется после настройки среды Node.js. Однако некоторые флаги, такие как --env-file или --openssl-config предназначены для чтения файлов до инициализации среды. В результате такие флаги не подчиняются правилам модели разрешений.
  • Невозможно запросить движки OpenSSL во время выполнения при включенной модели разрешений, что повлияет на встроенные модули криптографии, https и tls.
Ограничения и известные проблемы
  • При включенной модели разрешений Node.js может решать некоторые пути по-другому, чем при её отключении.
  • Символические ссылки будут переследовать даже в места за пределами набора путей, к которым был предоставлен доступ. Относительные символические ссылки могут разрешить доступ к произвольным файлам и каталогам. При запуске приложений с включенной моделью разрешений необходимо убедиться, что пути, к которым был предоставлен доступ, не содержат относительных символических ссылок.

© Joyent, Inc. and other Node contributors
Licensed under the MIT License.
Node.js is a trademark of Joyent, Inc. and is used with its permission.
We are not endorsed by or affiliated with Joyent.
https://nodejs.org/dist/latest-v20.x/docs/api/permissions.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API