1# Permissions 2 3Permissions can be used to control what system resources the 4Node.js process has access to or what actions the process can take 5with those resources. Permissions can also control what modules can 6be accessed by other modules. 7 8* [Module-based permissions](#module-based-permissions) control which files 9 or URLs are available to other modules during application execution. 10 This can be used to control what modules can be accessed by third-party 11 dependencies, for example. 12 13If you find a potential security vulnerability, please refer to our 14[Security Policy][]. 15 16## Module-based permissions 17 18### Policies 19 20<!--introduced_in=v11.8.0--> 21 22<!-- type=misc --> 23 24> Stability: 1 - Experimental 25 26<!-- name=policy --> 27 28Node.js contains experimental support for creating policies on loading code. 29 30Policies are a security feature intended to allow guarantees 31about what code Node.js is able to load. The use of policies assumes 32safe practices for the policy files such as ensuring that policy 33files cannot be overwritten by the Node.js application by using 34file permissions. 35 36A best practice would be to ensure that the policy manifest is read-only for 37the running Node.js application and that the file cannot be changed 38by the running Node.js application in any way. A typical setup would be to 39create the policy file as a different user id than the one running Node.js 40and granting read permissions to the user id running Node.js. 41 42#### Enabling 43 44<!-- type=misc --> 45 46The `--experimental-policy` flag can be used to enable features for policies 47when loading modules. 48 49Once this has been set, all modules must conform to a policy manifest file 50passed to the flag: 51 52```bash 53node --experimental-policy=policy.json app.js 54``` 55 56The policy manifest will be used to enforce constraints on code loaded by 57Node.js. 58 59To mitigate tampering with policy files on disk, an integrity for 60the policy file itself may be provided via `--policy-integrity`. 61This allows running `node` and asserting the policy file contents 62even if the file is changed on disk. 63 64```bash 65node --experimental-policy=policy.json --policy-integrity="sha384-SggXRQHwCG8g+DktYYzxkXRIkTiEYWBHqev0xnpCxYlqMBufKZHAHQM3/boDaI/0" app.js 66``` 67 68#### Features 69 70##### Error behavior 71 72When a policy check fails, Node.js by default will throw an error. 73It is possible to change the error behavior to one of a few possibilities 74by defining an "onerror" field in a policy manifest. The following values are 75available to change the behavior: 76 77* `"exit"`: will exit the process immediately. 78 No cleanup code will be allowed to run. 79* `"log"`: will log the error at the site of the failure. 80* `"throw"`: will throw a JS error at the site of the failure. This is the 81 default. 82 83```json 84{ 85 "onerror": "log", 86 "resources": { 87 "./app/checked.js": { 88 "integrity": "sha384-SggXRQHwCG8g+DktYYzxkXRIkTiEYWBHqev0xnpCxYlqMBufKZHAHQM3/boDaI/0" 89 } 90 } 91} 92``` 93 94##### Integrity checks 95 96Policy files must use integrity checks with Subresource Integrity strings 97compatible with the browser 98[integrity attribute](https://www.w3.org/TR/SRI/#the-integrity-attribute) 99associated with absolute URLs. 100 101When using `require()` or `import` all resources involved in loading are checked 102for integrity if a policy manifest has been specified. If a resource does not 103match the integrity listed in the manifest, an error will be thrown. 104 105An example policy file that would allow loading a file `checked.js`: 106 107```json 108{ 109 "resources": { 110 "./app/checked.js": { 111 "integrity": "sha384-SggXRQHwCG8g+DktYYzxkXRIkTiEYWBHqev0xnpCxYlqMBufKZHAHQM3/boDaI/0" 112 } 113 } 114} 115``` 116 117Each resource listed in the policy manifest can be of one the following 118formats to determine its location: 119 1201. A [relative-URL string][] to a resource from the manifest such as `./resource.js`, `../resource.js`, or `/resource.js`. 1212. A complete URL string to a resource such as `file:///resource.js`. 122 123When loading resources the entire URL must match including search parameters 124and hash fragment. `./a.js?b` will not be used when attempting to load 125`./a.js` and vice versa. 126 127To generate integrity strings, a script such as 128`node -e 'process.stdout.write("sha256-");process.stdin.pipe(crypto.createHash("sha256").setEncoding("base64")).pipe(process.stdout)' < FILE` 129can be used. 130 131Integrity can be specified as the boolean value `true` to accept any 132body for the resource which can be useful for local development. It is not 133recommended in production since it would allow unexpected alteration of 134resources to be considered valid. 135 136##### Dependency redirection 137 138An application may need to ship patched versions of modules or to prevent 139modules from allowing all modules access to all other modules. Redirection 140can be used by intercepting attempts to load the modules wishing to be 141replaced. 142 143```json 144{ 145 "resources": { 146 "./app/checked.js": { 147 "dependencies": { 148 "fs": true, 149 "os": "./app/node_modules/alt-os", 150 "http": { "import": true } 151 } 152 } 153 } 154} 155``` 156 157The dependencies are keyed by the requested specifier string and have values 158of either `true`, `null`, a string pointing to a module to be resolved, 159or a conditions object. 160 161The specifier string does not perform any searching and must match exactly what 162is provided to the `require()` or `import` except for a canonicalization step. 163Therefore, multiple specifiers may be needed in the policy if it uses multiple 164different strings to point to the same module (such as excluding the extension). 165 166Specifier strings are canonicalized but not resolved prior to be used for 167matching in order to have some compatibility with import maps, for example if a 168resource `file:///C:/app/server.js` was given the following redirection from a 169policy located at `file:///C:/app/policy.json`: 170 171```json 172{ 173 "resources": { 174 "file:///C:/app/utils.js": { 175 "dependencies": { 176 "./utils.js": "./utils-v2.js" 177 } 178 } 179 } 180} 181``` 182 183Any specifier used to load `file:///C:/app/utils.js` would then be intercepted 184and redirected to `file:///C:/app/utils-v2.js` instead regardless of using an 185absolute or relative specifier. However, if a specifier that is not an absolute 186or relative URL string is used, it would not be intercepted. So, if an import 187such as `import('#utils')` was used, it would not be intercepted. 188 189If the value of the redirection is `true`, a "dependencies" field at the top of 190the policy file will be used. If that field at the top of the policy file is 191`true` the default node searching algorithms are used to find the module. 192 193If the value of the redirection is a string, it is resolved relative to 194the manifest and then immediately used without searching. 195 196Any specifier string for which resolution is attempted and that is not listed in 197the dependencies results in an error according to the policy. 198 199Redirection does not prevent access to APIs through means such as direct access 200to `require.cache` or through `module.constructor` which allow access to 201loading modules. Policy redirection only affects specifiers to `require()` and 202`import`. Other means, such as to prevent undesired access to APIs through 203variables, are necessary to lock down that path of loading modules. 204 205A boolean value of `true` for the dependencies map can be specified to allow a 206module to load any specifier without redirection. This can be useful for local 207development and may have some valid usage in production, but should be used 208only with care after auditing a module to ensure its behavior is valid. 209 210Similar to `"exports"` in `package.json`, dependencies can also be specified to 211be objects containing conditions which branch how dependencies are loaded. In 212the preceding example, `"http"` is allowed when the `"import"` condition is 213part of loading it. 214 215A value of `null` for the resolved value causes the resolution to fail. This 216can be used to ensure some kinds of dynamic access are explicitly prevented. 217 218Unknown values for the resolved module location cause failures but are 219not guaranteed to be forward compatible. 220 221##### Example: Patched dependency 222 223Redirected dependencies can provide attenuated or modified functionality as fits 224the application. For example, log data about timing of function durations by 225wrapping the original: 226 227```js 228const original = require('fn'); 229module.exports = function fn(...args) { 230 console.time(); 231 try { 232 return new.target ? 233 Reflect.construct(original, args) : 234 Reflect.apply(original, this, args); 235 } finally { 236 console.timeEnd(); 237 } 238}; 239``` 240 241#### Scopes 242 243Use the `"scopes"` field of a manifest to set configuration for many resources 244at once. The `"scopes"` field works by matching resources by their segments. 245If a scope or resource includes `"cascade": true`, unknown specifiers will 246be searched for in their containing scope. The containing scope for cascading 247is found by recursively reducing the resource URL by removing segments for 248[special schemes][], keeping trailing `"/"` suffixes, and removing the query and 249hash fragment. This leads to the eventual reduction of the URL to its origin. 250If the URL is non-special the scope will be located by the URL's origin. If no 251scope is found for the origin or in the case of opaque origins, a protocol 252string can be used as a scope. If no scope is found for the URL's protocol, a 253final empty string `""` scope will be used. 254 255Note, `blob:` URLs adopt their origin from the path they contain, and so a scope 256of `"blob:https://nodejs.org"` will have no effect since no URL can have an 257origin of `blob:https://nodejs.org`; URLs starting with 258`blob:https://nodejs.org/` will use `https://nodejs.org` for its origin and 259thus `https:` for its protocol scope. For opaque origin `blob:` URLs they will 260have `blob:` for their protocol scope since they do not adopt origins. 261 262##### Example 263 264```json 265{ 266 "scopes": { 267 "file:///C:/app/": {}, 268 "file:": {}, 269 "": {} 270 } 271} 272``` 273 274Given a file located at `file:///C:/app/bin/main.js`, the following scopes would 275be checked in order: 276 2771. `"file:///C:/app/bin/"` 278 279This determines the policy for all file based resources within 280`"file:///C:/app/bin/"`. This is not in the `"scopes"` field of the policy and 281would be skipped. Adding this scope to the policy would cause it to be used 282prior to the `"file:///C:/app/"` scope. 283 2842. `"file:///C:/app/"` 285 286This determines the policy for all file based resources within 287`"file:///C:/app/"`. This is in the `"scopes"` field of the policy and it would 288determine the policy for the resource at `file:///C:/app/bin/main.js`. If the 289scope has `"cascade": true`, any unsatisfied queries about the resource would 290delegate to the next relevant scope for `file:///C:/app/bin/main.js`, `"file:"`. 291 2923. `"file:///C:/"` 293 294This determines the policy for all file based resources within `"file:///C:/"`. 295This is not in the `"scopes"` field of the policy and would be skipped. It would 296not be used for `file:///C:/app/bin/main.js` unless `"file:///"` is set to 297cascade or is not in the `"scopes"` of the policy. 298 2994. `"file:///"` 300 301This determines the policy for all file based resources on the `localhost`. This 302is not in the `"scopes"` field of the policy and would be skipped. It would not 303be used for `file:///C:/app/bin/main.js` unless `"file:///"` is set to cascade 304or is not in the `"scopes"` of the policy. 305 3065. `"file:"` 307 308This determines the policy for all file based resources. It would not be used 309for `file:///C:/app/bin/main.js` unless `"file:///"` is set to cascade or is not 310in the `"scopes"` of the policy. 311 3126. `""` 313 314This determines the policy for all resources. It would not be used for 315`file:///C:/app/bin/main.js` unless `"file:"` is set to cascade. 316 317##### Integrity using scopes 318 319Setting an integrity to `true` on a scope will set the integrity for any 320resource not found in the manifest to `true`. 321 322Setting an integrity to `null` on a scope will set the integrity for any 323resource not found in the manifest to fail matching. 324 325Not including an integrity is the same as setting the integrity to `null`. 326 327`"cascade"` for integrity checks will be ignored if `"integrity"` is explicitly 328set. 329 330The following example allows loading any file: 331 332```json 333{ 334 "scopes": { 335 "file:": { 336 "integrity": true 337 } 338 } 339} 340``` 341 342##### Dependency redirection using scopes 343 344The following example, would allow access to `fs` for all resources within 345`./app/`: 346 347```json 348{ 349 "resources": { 350 "./app/checked.js": { 351 "cascade": true, 352 "integrity": true 353 } 354 }, 355 "scopes": { 356 "./app/": { 357 "dependencies": { 358 "fs": true 359 } 360 } 361 } 362} 363``` 364 365The following example, would allow access to `fs` for all `data:` resources: 366 367```json 368{ 369 "resources": { 370 "data:text/javascript,import('node:fs');": { 371 "cascade": true, 372 "integrity": true 373 } 374 }, 375 "scopes": { 376 "data:": { 377 "dependencies": { 378 "fs": true 379 } 380 } 381 } 382} 383``` 384 385##### Example: import maps emulation 386 387Given an import map: 388 389```json 390{ 391 "imports": { 392 "react": "./app/node_modules/react/index.js" 393 }, 394 "scopes": { 395 "./ssr/": { 396 "react": "./app/node_modules/server-side-react/index.js" 397 } 398 } 399} 400``` 401 402```json 403{ 404 "dependencies": true, 405 "scopes": { 406 "": { 407 "cascade": true, 408 "dependencies": { 409 "react": "./app/node_modules/react/index.js" 410 } 411 }, 412 "./ssr/": { 413 "cascade": true, 414 "dependencies": { 415 "react": "./app/node_modules/server-side-react/index.js" 416 } 417 } 418 } 419} 420``` 421 422[Import maps][] assume you can get any resource by default. This means 423`"dependencies"` at the top level of the policy should be set to `true`. 424Policies require this to be opt-in since it enables all resources of the 425application cross linkage which doesn't make sense for many scenarios. They also 426assume any given scope has access to any scope above its allowed dependencies; 427all scopes emulating import maps must set `"cascade": true`. 428 429Import maps only have a single top level scope for their "imports". So for 430emulating `"imports"` use the `""` scope. For emulating `"scopes"` use the 431`"scopes"` in a similar manner to how `"scopes"` works in import maps. 432 433Caveats: Policies do not use string matching for various finding of scope. They 434do URL traversals. This means things like `blob:` and `data:` URLs might not be 435entirely interoperable between the two systems. For example import maps can 436partially match a `data:` or `blob:` URL by partitioning the URL on a `/` 437character, policies intentionally cannot. For `blob:` URLs import map scopes do 438not adopt the origin of the `blob:` URL. 439 440Additionally, import maps only work on `import` so it may be desirable to add a 441`"import"` condition to all dependency mappings. 442 443[Security Policy]: https://github.com/nodejs/node/blob/main/SECURITY.md 444[import maps]: https://url.spec.whatwg.org/#relative-url-with-fragment-string 445[relative-url string]: https://url.spec.whatwg.org/#relative-url-with-fragment-string 446[special schemes]: https://url.spec.whatwg.org/#special-scheme 447