-
Notifications
You must be signed in to change notification settings - Fork 23.1k
TrustedTypes: Function() constructor + eval() #42462
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
Changes from all commits
409c814
21eb527
002ac96
207586d
65a3738
b20397f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,7 +7,16 @@ browser-compat: javascript.builtins.Function.Function | |
| sidebar: jsref | ||
| --- | ||
|
|
||
| The **`Function()`** constructor creates {{jsxref("Function")}} objects. Calling the constructor directly can create functions dynamically, but suffers from security and similar (but far less significant) performance issues as {{jsxref("Global_Objects/eval", "eval()")}}. However, unlike `eval` (which may have access to the local scope), the `Function` constructor creates functions which execute in the global scope only. | ||
| > [!WARNING] | ||
| > The arguments passed this method are dynamically evaluated and executed as JavaScript. | ||
| > 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 always passing {{domxref("TrustedScript")}} 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 **`Function()`** constructor creates {{jsxref("Function")}} objects. | ||
| Calling the constructor directly can create functions dynamically, but suffers from security and similar (but far less significant) performance issues as {{jsxref("Global_Objects/eval", "eval()")}}. However, unlike `eval` (which may have access to the local scope), the `Function` constructor creates functions which execute in the global scope only. | ||
|
|
||
| {{InteractiveExample("JavaScript Demo: Function() constructor", "shorter")}} | ||
|
|
||
|
|
@@ -38,12 +47,24 @@ Function(arg1, arg2, /* …, */ argN, functionBody) | |
| ### Parameters | ||
|
|
||
| - `arg1`, …, `argN` {{optional_inline}} | ||
| - : Names to be used by the function as formal argument names. Each must be a string that corresponds to a valid JavaScript parameter (any of plain [identifier](/en-US/docs/Glossary/Identifier), [rest parameter](/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters), or [destructured](/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring) parameter, optionally with a [default](/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters)), or a list of such strings separated with commas. | ||
| - : {{domxref("TrustedScript")}} instances or strings specifying names to be used by the function as formal argument names. | ||
|
Collaborator
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. It feels weird that this is part of JavaScript, but has this dependency on a web API. I don't know enough about the JS docs to know if this is a problem.
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. @Josh-Cena This is a JavaScript native method that on a supporting browser might take a I am fine with this - in environments where However, if you have a specific way you'd like to address this in the
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.
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. I'll merge if no response before I wander off today. We can always tidy up later.
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. Off I go! Thanks @wbamberg |
||
| The value must correspond to a valid JavaScript parameter (any of plain [identifier](/en-US/docs/Glossary/Identifier), [rest parameter](/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters), or [destructured](/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring) parameter, optionally with a [default](/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters)), or a list of such strings separated with commas. | ||
|
|
||
| As the parameters are parsed in the same way as function expressions, whitespace and comments are accepted. For example: `"x", "theValue = 42", "[a, b] /* numbers */"` — or `"x, theValue = 42, [a, b] /* numbers */"`. (`"x, theValue = 42", "[a, b]"` is also correct, though very confusing to read.) | ||
| As the parameters are parsed in the same way as function expressions, whitespace and comments are accepted. | ||
| For example: `"x", "theValue = 42", "[a, b] /* numbers */"` — or `"x, theValue = 42, [a, b] /* numbers */"`. | ||
| (`"x, theValue = 42", "[a, b]"` is also correct, though very confusing to read.) | ||
|
|
||
| - `functionBody` | ||
| - : A string containing the JavaScript statements comprising the function definition. | ||
| - : A {{domxref("TrustedScript")}} or a string containing the JavaScript statements comprising the function definition. | ||
|
|
||
| ### Exceptions | ||
|
|
||
| - {{jsxref("SyntaxError")}} | ||
| - : Function parameter arguments can't be evaluated as valid identifiers, or the `functionBody` can't be parsed as a script. | ||
| - {{jsxref("TypeError")}} | ||
| - : Any parameter is a string when [Trusted Types](/en-US/docs/Web/API/Trusted_Types_API) are [enforced by a CSP](/en-US/docs/Web/API/Trusted_Types_API#using_a_csp_to_enforce_trusted_types) and no default policy is defined. | ||
|
|
||
| The method also throws any exception that occurs during evaluation of the code. | ||
|
|
||
| ## Description | ||
|
|
||
|
|
@@ -85,8 +106,41 @@ new Function("/*", "*/) {"); | |
| // Doesn't become "function anonymous(/*) {*/) {}" | ||
| ``` | ||
|
|
||
| ### Security considerations | ||
hamishwillee marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| The method can be used to execute arbitrary input passed to any parameter. | ||
| If the input is a potentially unsafe string provided by a user, this is a possible vector for [Cross-site-scripting (XSS)](/en-US/docs/Web/Security/Attacks/XSS) attacks. | ||
| For example, the following example assumes the `untrustedCode` was provided by a user: | ||
|
|
||
| ```js example-bad | ||
| const untrustedCode = "alert('Potentially evil code!');"; | ||
| const adder = new Function("a", "b", untrustedCode); | ||
| ``` | ||
|
|
||
| Websites with a [Content Security Policy (CSP)](/en-US/docs/Web/HTTP/Guides/CSP) that specifies [`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) will prevent such code running by default. | ||
|
|
||
| If you must allow the scripts to run via `Function()` you can mitigate these issues by always assigning {{domxref("TrustedScript")}} objects instead of strings, 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. | ||
| This ensures that the input is passed through a transformation function. | ||
|
|
||
| To allow `Function()` to run, you will additionally need to specify the [`trusted-types-eval` keyword](/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy#trusted-types-eval) in your CSP `script-src` directive. | ||
|
|
||
| The [`unsafe-eval`](/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy#unsafe-eval) keyword also allows `Function()`, but is much less safe then `trusted-types-eval` because it would allow execution even on browsers that do not support trusted types. | ||
|
|
||
| For example, the required CSP for your site might look like this: | ||
|
|
||
| ```http | ||
| Content-Security-Policy: require-trusted-types-for 'script'; script-src '<your_allowlist>' 'trusted-types-eval' | ||
| ``` | ||
|
|
||
| The behavior of the transformation function will depend on the specific use case that requires a user provided script. | ||
| If possible you should lock the allowed scripts to exactly the code that you trust to run. | ||
| If that is not possible, you might allow or block the use of certain functions within the provided string. | ||
|
|
||
| ## Examples | ||
|
|
||
| Note that these examples omit the use of trusted types for brevity. | ||
| For code showing the usual approach, see [Using `TrustedScript`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval#using_trustedscript) in `eval()`. | ||
|
|
||
| ### Specifying arguments with the Function constructor | ||
|
|
||
| The following code creates a `Function` object that takes two arguments. | ||
|
|
@@ -147,6 +201,7 @@ sayHello("world"); | |
|
|
||
| ## See also | ||
|
|
||
| - [Using the function constructor](/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval#using_the_function_constructor) in `eval()` | ||
| - [`function`](/en-US/docs/Web/JavaScript/Reference/Statements/function) | ||
| - [`function` expression](/en-US/docs/Web/JavaScript/Reference/Operators/function) | ||
| - {{jsxref("Functions", "Functions", "", 1)}} | ||
Uh oh!
There was an error while loading. Please reload this page.