-
Notifications
You must be signed in to change notification settings - Fork 23k
TrustedTypes: WorkerGlobalScope: importScripts() #42396
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
hamishwillee
wants to merge
2
commits into
mdn:main
Choose a base branch
from
hamishwillee:tt_importscripts
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,20 +8,29 @@ browser-compat: api.WorkerGlobalScope.importScripts | |
|
|
||
| {{APIRef("Web Workers API")}}{{AvailableInWorkers("worker")}} | ||
|
|
||
| > [!WARNING] | ||
| > The parameters passed to this method represent the URLs of classic scripts to be imported into a worker. | ||
| > APIs like this are known as [injection sinks](/en-US/docs/Web/API/Trusted_Types_API#concepts_and_usage), and are potentially a vector for [cross-site scripting (XSS)](/en-US/docs/Web/Security/Attacks/XSS) attacks. | ||
| > | ||
| > You can mitigate this risk by having a [Content Security Policy (CSP)](/en-US/docs/Web/HTTP/Guides/CSP) that restricts the locations from which scripts can be loaded, and by always assigning {{domxref("TrustedScriptURL")}} objects instead of strings and [enforcing trusted types](/en-US/docs/Web/API/Trusted_Types_API#using_a_csp_to_enforce_trusted_types). | ||
| > See [Security considerations](#security_considerations) for more information. | ||
|
|
||
| The **`importScripts()`** method of the {{domxref("WorkerGlobalScope")}} interface synchronously imports one or more scripts into the worker's scope. | ||
|
|
||
| ## Syntax | ||
|
|
||
| ```js-nolint | ||
| importScripts(path0) | ||
| importScripts(path0, path1) | ||
| importScripts(path0, path1, /* …, */ pathN) | ||
| importScripts(url0) | ||
| importScripts(url0, url1) | ||
| importScripts(url0, url1, /* …, */ urlN) | ||
| ``` | ||
|
|
||
| ### Parameters | ||
|
|
||
| - `pathN` | ||
| - : A string value representing the URL of the script to be imported. The URL may be absolute or relative. If the URL is relative, it is relative to the worker entry script's URL. | ||
| - `urlN` | ||
| - : A {{domxref("TrustedScriptURL")}} instance or a string representing the URL of the script to be imported. | ||
| The URL may be absolute or relative. | ||
| If the URL is relative, it is relative to the worker entry script's URL. | ||
|
|
||
| ### Return value | ||
|
|
||
|
|
@@ -30,22 +39,93 @@ None ({{jsxref("undefined")}}). | |
| ### Exceptions | ||
|
|
||
| - `NetworkError` | ||
| - : Imported scripts were served without a `text/javascript` MIME type or without one of the permitted [legacy JavaScript MIME types](/en-US/docs/Web/HTTP/Guides/MIME_types#legacy_javascript_mime_types). | ||
| - : Imported scripts were served without a `text/javascript` media (MIME) type or without one of the permitted [legacy JavaScript MIME types](/en-US/docs/Web/HTTP/Guides/MIME_types#legacy_javascript_mime_types). | ||
| - {{jsxref("TypeError")}} | ||
| - : Thrown if the current {{domxref("WorkerGlobalScope")}} is a module. Use [`import`](/en-US/docs/Web/JavaScript/Reference/Statements/import) instead. | ||
| - : Thrown if the current {{domxref("WorkerGlobalScope")}} is a module (use [`import`](/en-US/docs/Web/JavaScript/Reference/Statements/import) instead). | ||
| It may also happen if any parameter is not a {{domxref("TrustedScriptURL")}} and the site is [enforcing trusted types](/en-US/docs/Web/API/Trusted_Types_API#using_a_csp_to_enforce_trusted_types). | ||
|
|
||
| ## Description | ||
|
|
||
| The **`importScripts()`** method synchronously imports one or more scripts into the worker's scope. | ||
|
|
||
| Unlike the initial classic module script, which must be same-origin with its document, this method can import scripts that are cross-origin unless blocked by a resource {{httpheader("Cross-Origin-Resource-Policy")}} or some other security mechanism. | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is where I'd add a bit more on the importing rules for classic scripts https://github.com/mdn/content/pull/42396/files#r2621680224 |
||
|
|
||
| ### Security considerations | ||
|
|
||
| The parameters specify scripts to be imported into the scope of a classic worker. | ||
| If the input is provided by a user, this is a possible vector for [cross-site scripting (XSS)](/en-US/docs/Web/Security/Attacks/XSS) attacks. | ||
|
|
||
| It is extremely risky to accept and execute arbitrary URLs from untrusted origins. | ||
| A website should control what scripts that are allowed to run using a [Content Security Policy (CSP)](/en-US/docs/Web/HTTP/Guides/CSP) with the [`worker-src`](/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/worker-src) directive (or a fallback defined in [`script-src`](/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/script-src) or [`default-src`](/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/default-src)). | ||
| This can restrict scripts to those from the current origin, or a specific set of origins, or even particular files. | ||
|
|
||
| If you're using this property and [enforcing trusted types](/en-US/docs/Web/API/Trusted_Types_API#using_a_csp_to_enforce_trusted_types) (using the [`require-trusted-types-for`](/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for) CSP directive), you will need to always assign {{domxref("TrustedScriptURL")}} objects instead of strings. | ||
| This ensures that the input is passed through a transformation function, which has the chance to reject or modify the URL before it is injected. | ||
|
|
||
| ## Examples | ||
|
|
||
| If you had some functionality written in a separate script called `foo.js` that you wanted to use inside `worker.js`, you could import it using the following line: | ||
| ### Basic usage | ||
|
|
||
| If you had some functionality written in a separate script called `foo.js` in the same directory as `worker.js`, you could import it into the worker using the following line: | ||
|
|
||
| ```js | ||
| importScripts("foo.js"); | ||
| ``` | ||
|
|
||
| `foo.js` should be in the same URL subtree as the worker's entry point — for example, if this worker was created with `new Worker("worker.js")`, then `worker.js` is the entry point. If `worker.js` is at `https://example.com/scripts/worker.js`, then `foo.js` should be at `https://example.com/scripts/foo.js`. | ||
|
|
||
| `importScripts()` and `self.importScripts()` are effectively equivalent — both represent `importScripts()` being called from inside the worker's inner scope. | ||
|
|
||
| Note that in the next section we show you how to pass a `TrustedScriptURL` instead of a string. | ||
| This was omitted in this example for brevity, but is recommended in production code. | ||
|
|
||
| ### Using TrustedScriptURL | ||
|
|
||
| To mitigate the risk of XSS, we should always assign `TrustedScriptURL` instances to each of the parameters. | ||
| We also need to do this if we're enforcing trusted types for other reasons and we want to allow some script sources that have been permitted (by `CSP: worker-src`). | ||
|
|
||
| Trusted types are not yet supported on all browsers, so first we define the [trusted types tinyfill](/en-US/docs/Web/API/Trusted_Types_API#trusted_types_tinyfill). | ||
| This acts as a transparent replacement for the trusted types JavaScript API: | ||
|
|
||
| ```js | ||
| if (typeof trustedTypes === "undefined") | ||
| trustedTypes = { createPolicy: (n, rules) => rules }; | ||
| ``` | ||
|
|
||
| Next we create a {{domxref("TrustedTypePolicy")}} that defines a {{domxref("TrustedTypePolicy/createScriptURL", "createScriptURL()")}} method for transforming input strings into {{domxref("TrustedScriptURL")}} instances. | ||
|
|
||
| For the purpose of this example we'll assume that we want to allow a predefined set of URLs in the `scriptAllowList` array and log any other scripts. | ||
|
|
||
| ```js | ||
| const scriptAllowList = [ | ||
| // Some list of allowed URLs | ||
| ]; | ||
| const policy = trustedTypes.createPolicy("script-url-policy", { | ||
| createScriptURL(input) { | ||
| if (scriptAllowList.includes(input)) { | ||
| return input; // allow the script | ||
| } | ||
| console.log(`Script not in scriptAllowList: ${input}`); | ||
| return ""; // Block the script | ||
| }, | ||
| }); | ||
| ``` | ||
|
|
||
| Then we use the `policy` object to create a `trustedScript` object from a potentially unsafe input string: | ||
|
|
||
| ```js | ||
| // The potentially malicious string | ||
| // We won't be including untrustedScript in our scriptAllowList array | ||
| const untrustedScript = "https://evil.example.com/import_worker.js"; | ||
|
|
||
| // Create a TrustedScriptURL instance using the policy | ||
| const trustedScriptURL = policy.createScriptURL(untrustedScript); | ||
| ``` | ||
|
|
||
| The `trustedScriptURL` property can now be used when importing the script in a classic worker: | ||
|
|
||
| ```js | ||
| importScripts(trustedScriptURL); | ||
| ``` | ||
|
|
||
| ## Specifications | ||
|
|
||
| {{Specifications}} | ||
|
|
||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wbamberg This follows same pattern as the others. The method is used to import (one or more) classic scripts into a classic module.
I have done quite a lot of testing.
none. That's my testing anyway.Essentially it looks like for this method you can import what you like from wherever you like unless blocked by the server resource policy you are importing from.
FYI, my testing is here https://github.com/hamishwillee/various_webapi_tests/tree/main/classic_worker_import - this uses a caddyfile - caddy allows you to set up a server with headers, https and certificate with no real effort..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PS I have not tried to capture all that in this doc. Waiting to see your thoughts.