From eee3f9b2d2e9dff25c82316015d29b3100f318a5 Mon Sep 17 00:00:00 2001 From: Brad Nelson Date: Tue, 31 Oct 2017 22:30:44 -0700 Subject: [PATCH 01/59] Adding CSP proposal. --- proposals/CSP.md | 163 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 proposals/CSP.md diff --git a/proposals/CSP.md b/proposals/CSP.md new file mode 100644 index 0000000000..5bd03177b6 --- /dev/null +++ b/proposals/CSP.md @@ -0,0 +1,163 @@ +# WebAssembly Content Security Policy + +This proposal attempts to homogenize existing WebAssembly implementation's +handling of Content Security Policy. + +It also attempts to extend CSP to better support WebAssemble use cases. + +## Behavior of Current Implementations + +All implementations currently permit all the WebAssembly operations they +support if there is no Content-Security-Policy specified. + +All implementations currently permit all the WebAssembly operations they +support if there is a Content-Security-Policy specified +and `script-src` includes the 'unsafe-eval' directive. + +Implementations vary as to which WebAssembly operations are allowed +if there is a Content-Security-Policy specified and +`script-src` does not include the 'unsafe-eval' directive. +The following table describes which operations are allowed in this case: + +Operation | Chrome | Safari | Firefox | Edge +--- | --- | --- | --- | --- +WebAssembly.validate | yes | yes | yes | yes +new WebAssembly.Module | no | yes | yes | yes +WebAssembly.compile | no | yes | yes | yes +WebAssembly.compileStreaming | no | yes | yes | yes +WebAssembly.instantiate | no | no | yes | yes +WebAssembly.instantiateStreaming | no | no | yes | yes +new WebAssembly.CompileError | yes | yes | yes | yes +new WebAssembly.LinkError | yes | yes | yes | yes +new WebAssembly.Table | yes | no | yes | yes +new WebAssembly.Memory | yes | no | yes | yes + +The type of exception thrown when one of the above operations is disallowed +also varies by implementation. +This table lists the exception type for each implementation: + +Browser | Thrown if disallowed +--- | -- +Chrome | WebAssembly.CompileError: Wasm code generation disallowed in this context +Safari | EvalError +Firefox | N/A +Edge | ?? + +For references here is how each brower handles eval(): + +Browser | Thrown if disallowed +--- | -- +Chrome | EvalError +Safari | EvalError +Firefox | Disallows script (uncatchable) +Edge | ?? + + +## Proposed Homogenization of Existing Behavior + +Motivating Principles: + +* Be conservative about what is allowed. +* Allow operations which cannot be origin bound within + the current API surface (Chrome's behavior). + * Allow Memory and Table objects, because they are tied to + the current origin, + will be needed when compilation / instantiation is origin bound, + have no parameters allowing an explicit origin. + * Disallow compilation, as it can be used to exercise WebAssembly + code compilation if an injection attack is present. +* Throw an EvalError (Safari's behavior), as this is what both + Chrome and Safari do for eval(). NOTE: Firefox's behavior is even more + conservative, but this might be challenging for others as it is more + strict than for eval(). + +This table describes which operations should be allowed when +there is a Content-Security-Policy specified and +`script-src` does not include the 'unsafe-eval' directive: + +Operation | Result +--- | --- +WebAssembly.validate | yes +new WebAssembly.Module | no +WebAssembly.compile | no +WebAssembly.compileStreaming | no +WebAssembly.instantiate | no +WebAssembly.instantiateStreaming | no +new WebAssembly.CompileError | yes +new WebAssembly.LinkError | yes +new WebAssembly.Table | yes +new WebAssembly.Memory | yes + + +## Proposed 'wasm-eval' Directive + +WebAssembly compilation is less prone to being spoofed in the way +JavaScript is. Further, WebAssembly has an explicitly specified scope, +further reducing the likelihood of injection attacks. + +While origin bound / known hash operations are always safer, +it is useful to have a mechanism to allow WebAssembly content +in a CSP policy that would otherwise disallow it, without being +required to also allow JavaScript eval(). + +NOTE: Providing a directive to allow JavaScript eval() without WebAssembly +doesn't seem immediately useful, and so has been left out intentionally. + +We propose: +* Allow the 'wasm-eval' directive under each directive that currently + supports 'unsafe-eval' (this is currently all directives because + directives can defer to each other). +* For the `script-src` directive (directly or by reference), + interpret 'wasm-eval' to mean + that all WebAssembly operations should be allowed. + (Without allowing eval()). + + +## Proposed Origin Bound Permission + +In order to make WebAssembly more useful within the spirit of CSP, +we should permit `Response` objects to carry trusted origin information. +This will allow compilation and instantiation of WebAssembly +in a natural way within a CSP. + +Proposed Changes: +* Response.url will be "hardened" to allow it (or it with a taint track bit) + to be trusted to carry information regarding the origin of a fetch + response. +* An immutable opaque bit mimeTypeWasm will be added to Response to capture + whether the original Response had mime type 'application/wasm'. + * Question: Does this interfere with service worker? +* WebAssembly compilation / instantiation requests that would + be allowed if they were script src's for non-inline JavaScript + which also have mimeTypeWasm, + will also be allowed for WebAssembly. + * This applies to hashes, or to origin whitelisting. +* This sub-proposal only affects WebAssembly.compileStreaming + and WebAssembly.instatiateStreaming + +### Examples + +``` +Content-Security-Policy: script-src 'self'; + +WebAssembly.compileStreaming(fetch('/foo.wasm')); // OK +WebAssembly.instantiateStreaming(fetch('/foo.wasm')); // OK +WebAssembly.compileStreaming(fetch('/foo.js')); // BAD: mime type +WebAssembly.instantiateStreaming(fetch('/foo.js')); // BAD: mime type +WebAssembly.compileStreaming(fetch('http://yo.com/foo.wasm')); // BAD: cross origin +WebAssembly.instantiateStreaming(fetch('http://yo.com/foo.wasm')); // BAD: cross origin +``` + +``` +Content-Security-Policy: script-src http://yo.com; + +WebAssembly.compileStreaming(fetch('http://yo.com/foo.wasm')); // OK +WebAssembly.instantiateStreaming(fetch('http://yo.com/foo.wasm')); // OK +``` + +``` +Content-Security-Policy: script-src 'sha256-123...456'; + +WebAssembly.compileStreaming(fetch('http://baz.com/hash123..456.wasm')); // OK +WebAssembly.instantiateStreaming(fetch('http://baz.com/hash123..456.wasm')); // OK +``` From d69bc5db8e0a2e726bbdb16a821fca8d841a3e02 Mon Sep 17 00:00:00 2001 From: Brad Nelson Date: Sun, 5 Nov 2017 20:27:55 -0800 Subject: [PATCH 02/59] Update README. --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 26d58a3a5c..6c6d8726dd 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,15 @@ [![Build Status](https://travis-ci.org/WebAssembly/spec.svg?branch=master)](https://travis-ci.org/WebAssembly/spec) +# Content Security Policy Proposal for WebAssembly + +This repository is a clone of github.com/WebAssembly/spec/. It is meant for +discussion, prototype specification and implementation of a proposal +to add better Content Security Policy (CSP) support to WebAssembly. + +See the [overview](proposals/CSP.md) for a summary of the proposal. + +Original README from upstream repository follows... + # spec This repository holds the sources for the WebAssembly draft specification From 7aa2d378c7000c42d3ac8853c2e16f3d39c7ed9b Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 6 Dec 2017 15:46:53 -0800 Subject: [PATCH 03/59] Provide background on CSP threat model and use cases Issue #1 --- proposals/CSP.md | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index 5bd03177b6..74de1bc1d4 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -1,10 +1,55 @@ # WebAssembly Content Security Policy This proposal attempts to homogenize existing WebAssembly implementation's -handling of Content Security Policy. +handling of Content Security Policy (CSP). It also attempts to extend CSP to better support WebAssemble use cases. +## Background: CSP Threat Model and Use Cases + +This section describes the attacks that CSP is meant to protect +against. WebAssembly's handling of CSP should respect this threat model. + +CSP, broadly, allows developers to control what resources can be loaded as part +of a site. These resources can include images, audio, video, or scripts. Loading +untrusted resources can lead to a variety of undesirable outcomes. Malicious +scripts could exfiltrate data from the site. Images could display misleading or +incorrect information. Fetching resources leaks information about the user to +untrusted third parties. + +While these threats could be protected against in other ways, CSP allows a small +set of security experts to define a comprehensive policy in one place to prevent +accidentally loading untrusted resources into the site. + +### Out of Scope Threats + +* **Bugs in the browser**. We assume correct implementations of image decoders, + script compilers, etc. CSP does not protect against malicious inputs that can, + for example, trigger buffer overflows. +* **Resource exhaustion**. Computation performed by scripts uses memory and CPU + time and can therefore cause a denial of service on the browser. Protecting + against this is one reason site owners use CSP, but denial of service is not a + first order consideration for CSP. Scripts are dangerous not because of their + resource consumption but because of other effects that can cause. + + +## WebAssembly and CSP + +A WebAssembly Instance is made up of the code, or Wasm bytes, and an import +object. The import object defines the capabilities of the instance, and +therefore the worst case security behavior. An instance with an empty import +object cannot cause any effects and is therefore safe to run. If it were +possible to vet the import object, it would be safe to create instances and run +from untrusted Wasm code because the behavior of the code would be bounded by +the capabilities of the import object. In practice, vetting an import object is +extremely difficult in JavaScript; it is easy to accidentally give access to the +global object. + +CSP turns the problem around. Assuming unrestricted capabilities, what code is +the developer willing to run on their site? Thus for WebAssembly, CSP will be +used to define what sources for Wasm bytes are trusted to instantiate and run. + + ## Behavior of Current Implementations All implementations currently permit all the WebAssembly operations they From 14755e63dbd6137b19897868cdff9529d377afda Mon Sep 17 00:00:00 2001 From: Brad Nelson Date: Tue, 20 Feb 2018 17:22:16 -0800 Subject: [PATCH 04/59] Add table detailing combinations. --- proposals/CSP.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/proposals/CSP.md b/proposals/CSP.md index 5bd03177b6..c1505c1c40 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -134,6 +134,23 @@ Proposed Changes: * This applies to hashes, or to origin whitelisting. * This sub-proposal only affects WebAssembly.compileStreaming and WebAssembly.instatiateStreaming + +### Total Behavior + +The desired end state with both of these looks something like this: + +Operation | default | unsafe-eval | wasm-eval | unsafe-eval + wasm-eval | w/ SRI ok | w/o SRI bad +--- | --- | --- | --- | -- | -- | -- +WebAssembly.validate | allow | disallow | allow | allow | N/A | N/A +new WebAssembly.Module | allow | allow if from instantiateCompile | allow | allow | allow if from instantiateCompile | disallow if from instantiateCompile +WebAssembly.compile | allow | disallow | allow | allow | N/A | N/A +WebAssembly.compileStreaming | based on SRI | based on SRI | based on SRI | based on SRI | allow | disallow +WebAssembly.instantiate | allow | allow if from instantiateCompile | allow | allow | allow if from instantiateCompile | disallow if from instantiateCompile +WebAssembly.instantiateStreaming | based on SRI | based on SRI | based on SRI | based on SRI | allow | disallow +new WebAssembly.CompileError | allow | allow | allow | allow | allow | allow +new WebAssembly.LinkError | allow | allow | allow | allow | allow | allow +new WebAssembly.Table | allow | allow | allow | allow | allow | allow +new WebAssembly.Memory | allow | allow | allow | allow | allow | allow ### Examples From ed2c962d9541e95cc969439502cbb4a2d72ee8d4 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Fri, 2 Mar 2018 15:28:40 -0800 Subject: [PATCH 05/59] Summarize API behavior and threats relative to CSP --- proposals/CSP.md | 77 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/proposals/CSP.md b/proposals/CSP.md index aaee520e4f..a6b9d69281 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -49,6 +49,83 @@ CSP turns the problem around. Assuming unrestricted capabilities, what code is the developer willing to run on their site? Thus for WebAssembly, CSP will be used to define what sources for Wasm bytes are trusted to instantiate and run. +### Summary of WebAssembly APIs and Their Risks + +This section introduces the APIs provided by WebAssembly that are relevant to +Content Security Policy. + +Executing WebAssembly has several steps. First there are the raw WebAssembly +bytes, which typically are loaded using the [fetch +API](https://fetch.spec.whatwg.org/). Next, the bytes are compiled using +`WebAssembly.compile` or `WebAssembly.compileStreaming` into a +`WebAssembly.Module`. This module is not yet executable, but WebAssembly +implementations may choose to translate the WebAssembly code into machine code +at this step (Chrome does this, WebKit does not). Finally, a WebAssembly module +is combined with an _import object_ using `WebAssembly.instantiate` to create an +`WebAssembly.Instance` object. The import object, broadly, defines the +capabilities of the resulting instance, oprtionally including a +`WebAssembly.Memory`, bindings for the WebAssembly function imports, and an +indirect function call table. It is at this point that the WebAssembly code is +actually executable, as the host code can call WebAssembly functions through the +instance's exports. + +These steps provide the core of the WebAssembly API, but there are several other +methods provided as well. These are summarized below along with their risks that +are related to CSP. + +[**`WebAssembly.validate`**](https://webassembly.github.io/spec/js-api/index.html#dom-webassembly-validate) +checks whether the given bytes comprise a valid WebAssembly program. In other +words, it checks whether the bytes are syntactically correct and valid according +to the WebAssembly type system. + +_Risks:_ None. + +[**`new WebAssembly.Module`**](https://webassembly.github.io/spec/js-api/index.html#dom-module-module) +synchronously creates a `WebAssembly.Module` from WebAssembly bytes. This is a +synchronous version of `WebAssembly.compile`. + +_Risks:_ many implementations will generate machine code at this step, even +though it is not yet exposed as executable code to the surrounding program. It's +possible that this code be used to build an exploit by taking advantage of +another bug in the implementation. + +[**`WebAssembly.compile`**](https://webassembly.github.io/spec/js-api/index.html#dom-webassembly-compile) +provides a `Promise` that resolves to a `WebAssembly.Module` generated from the +provided WebAssembly bytes. This is an asynchronous version of `new +WebAssembly.Module`. + +_Risks:_ equivalent to `new WebAssembly.Module`. + +[**`WebAssembly.compileStreaming`**](https://webassembly.github.io/spec/web-api/index.html#dom-webassembly-compilestreaming) +creates a `WebAssembly.Module` from the WebAssembly bytes contained in the +provided `Response` object. + +_Risks:_ equivalent to `new WebAssembly.Module`. + +[**`WebAssembly.instantiate`**](https://webassembly.github.io/spec/js-api/index.html#dom-webassembly-instantiate) +accepts either WebAssembly bytes or a `WebAssembly.Module` and an import object. +The function returns a `WebAssembly.Instance` that allows executing the +WebAssembly code. Is WebAssembly bytes are provided, `instantiate` will first +perform the steps of `WebAssembly.compile`. + +_Risks:_ loads executable code into the running program. This code is confined, +being only able to access objects reachable from the import object. The instance +does not have unrestricted access to the JavaScript global object. + +[**`WebAssembly.instantiateStreaming`**](https://webassembly.github.io/spec/web-api/index.html#dom-webassembly-instantiatestreaming) +accepts a `Response` containing WebAssembly bytes and an import object, performs +the operations behind `WebAssembly.compileStreaming` on these bytes and then +creates a `WebAssembly.Instance`. + +_Risks:_ equivalent to `WebAssembly.instantiate`. + +### Recommended Application of CSP + +Given the threat model for CSP, operations that load executable code should be +subject to CSP restrictions. This would cover `WebAssembly.instantiate` and +`WebAssembly.instantiateStreaming`. There are risks with `WebAssembly.compile` +and `WebAssembly.compileStreaming`, but these risks are explicitly outside the +CSP threat model. ## Behavior of Current Implementations From 21342e302acda1e8b32cd27078a8f713652ad9c9 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Fri, 2 Mar 2018 17:41:36 -0800 Subject: [PATCH 06/59] Fix typos --- proposals/CSP.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index a6b9d69281..3d18c634eb 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -63,7 +63,7 @@ implementations may choose to translate the WebAssembly code into machine code at this step (Chrome does this, WebKit does not). Finally, a WebAssembly module is combined with an _import object_ using `WebAssembly.instantiate` to create an `WebAssembly.Instance` object. The import object, broadly, defines the -capabilities of the resulting instance, oprtionally including a +capabilities of the resulting instance, optionally including a `WebAssembly.Memory`, bindings for the WebAssembly function imports, and an indirect function call table. It is at this point that the WebAssembly code is actually executable, as the host code can call WebAssembly functions through the @@ -105,7 +105,7 @@ _Risks:_ equivalent to `new WebAssembly.Module`. [**`WebAssembly.instantiate`**](https://webassembly.github.io/spec/js-api/index.html#dom-webassembly-instantiate) accepts either WebAssembly bytes or a `WebAssembly.Module` and an import object. The function returns a `WebAssembly.Instance` that allows executing the -WebAssembly code. Is WebAssembly bytes are provided, `instantiate` will first +WebAssembly code. If WebAssembly bytes are provided, `instantiate` will first perform the steps of `WebAssembly.compile`. _Risks:_ loads executable code into the running program. This code is confined, From 0659dc5ddc32502d573d295874fe0a231fa265a0 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Fri, 2 Mar 2018 17:44:47 -0800 Subject: [PATCH 07/59] Reaffirm out of scope risks --- proposals/CSP.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index 3d18c634eb..6239dca296 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -87,7 +87,8 @@ synchronous version of `WebAssembly.compile`. _Risks:_ many implementations will generate machine code at this step, even though it is not yet exposed as executable code to the surrounding program. It's possible that this code be used to build an exploit by taking advantage of -another bug in the implementation. +another bug in the implementation. This risk is explicitly out of scope for the +threat model we are working under. [**`WebAssembly.compile`**](https://webassembly.github.io/spec/js-api/index.html#dom-webassembly-compile) provides a `Promise` that resolves to a `WebAssembly.Module` generated from the From 7d3b908100c5d9c2372044f5db306c070e8bf687 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Thu, 8 Mar 2018 15:06:34 -0800 Subject: [PATCH 08/59] Starting to define abstract operation hooks --- document/js-api/index.bs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 567ff9c749..27bb20ae3e 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -244,6 +244,7 @@ namespace WebAssembly { Promise<WebAssemblyInstantiatedSource> instantiate( BufferSource bytes, optional object importObject); + Promise<Instance> instantiate( Module moduleObject, optional object importObject); }; @@ -501,6 +502,7 @@ interface Module { The Module(bytes) constructor, when invoked, performs the follwing steps: 1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|. + 1. Perform [$HostEnsureCanCompileWasmBytes()$] 1. [=Compile a WebAssembly module|Compile the WebAssembly module=] |stableBytes| and store the result as |module|. 1. If |module| is [=error=], throw a {{CompileError}} exception. 1. [=Construct a WebAssembly module object=] from |module| and |bytes|, and return the result. @@ -875,3 +877,16 @@ same class of exception is thrown as for out of memory conditions in JavaScript. The particular exception here is implementation-defined in both cases. Note: ECMAScript doesn't specify any sort of behavior on out-of-memory conditions; implementations have been observed to throw OOMError and to crash. Either is valid here. + +

Implementation-defined Operations

+ +

HostEnsureCanCompileWasmBytes()

+ +HostEnsureCanCompileWasmBytes is an implementation-defined abstract operation +that allows host environments to block certain WebAssembly functions which +compile bytes into WebAssembly code. + +An implementation of HostEnsureCanCompileWasmBytes may complete normally or +abruptly. Any abrupt completions will be propagated to its callers. The default +implementation of HostEnsureCanCompileWasmBytes is to unconditionally return an +empty normal completion. From d2caac350a75ff2b7fb2104452624777fc714104 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Thu, 8 Mar 2018 15:40:14 -0800 Subject: [PATCH 09/59] Add HostEnsureCanCompileWasmBytes hook for CSP --- document/js-api/index.bs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 27bb20ae3e..993a7a967e 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -304,6 +304,7 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
The compile(bytes) method, when invoked, performs the following steps: 1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|. + 1. Perform [$HostEnsureCanCompileWasmBytes(bytes)|HostEnsureCanCompileWasmBytes(stableBytes)$] 1. Let |promise| be [=a new promise=]. 1. [=Asynchronously compile a WebAssembly module=] from |stableBytes| with |promise|. 1. Return |promise|. @@ -410,6 +411,7 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
The instantiate(bytes, importObject) method, when invoked, performs the following steps: 1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|. + 1. Perform [$HostEnsureCanCompileWasmBytes(bytes)|HostEnsureCanCompileWasmBytes(stableBytes)$] 1. Let |promiseOfModule| be [=a new promise=]. 1. [=Asynchronously compile a WebAssembly module=] from |stableBytes| with |promiseOfModule|. 1. [=Instantiate a promise of a module|Instantiate=] |promiseOfModule| with imports |importObject| and return the result. @@ -502,7 +504,7 @@ interface Module { The Module(bytes) constructor, when invoked, performs the follwing steps: 1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|. - 1. Perform [$HostEnsureCanCompileWasmBytes()$] + 1. Perform [$HostEnsureCanCompileWasmBytes(bytes)|HostEnsureCanCompileWasmBytes(stableBytes)$] 1. [=Compile a WebAssembly module|Compile the WebAssembly module=] |stableBytes| and store the result as |module|. 1. If |module| is [=error=], throw a {{CompileError}} exception. 1. [=Construct a WebAssembly module object=] from |module| and |bytes|, and return the result. @@ -880,9 +882,9 @@ Note: ECMAScript doesn't specify any sort of behavior on out-of-memory condition

Implementation-defined Operations

-

HostEnsureCanCompileWasmBytes()

+

HostEnsureCanCompileWasmBytes(bytes)

-HostEnsureCanCompileWasmBytes is an implementation-defined abstract operation +HostEnsureCanCompileWasmBytes(bytes) is an implementation-defined abstract operation that allows host environments to block certain WebAssembly functions which compile bytes into WebAssembly code. From e22a3665391f17067fa9714d51f334232184c036 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Thu, 8 Mar 2018 16:07:29 -0800 Subject: [PATCH 10/59] Add HostEnsureCanCompileWasmResponse for interacting with CSP --- document/web-api/index.bs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/document/web-api/index.bs b/document/web-api/index.bs index ba62bc4875..2342c19fc5 100644 --- a/document/web-api/index.bs +++ b/document/web-api/index.bs @@ -112,6 +112,7 @@ Note: This algorithm accepts a {{Response}} object, or a 4. If |response| is not [=CORS-same-origin=], [=reject=] |returnValue| with a {{TypeError}} and abort these substeps. 1. If |response|'s [=response/status=] is not an [=ok status=], [=reject=] |returnValue| with a {{TypeError}} and abort these substeps. + 1. Perform [$HostEnsureCanCompileWasmResponse(response)$] 1. [=Consume body|consume=] |response|'s body as an {{ArrayBuffer}}, and let |bodyPromise| be the result. Note: Although it is specified here that the response is consumed entirely before compilation proceeds, that is purely for ease of specification; implementations are likely to instead perform processing in a streaming fashion. The different is unobservable, and thus the simpler model is specified. @@ -125,6 +126,17 @@ Note: This algorithm accepts a {{Response}} object, or a 1. Return |returnValue|.
+

HostEnsureCanCompileWasmResponse(response)

+ +HostEnsureCanCompileWasmResponse(response) is an implementation-defined abstract operation +that allows host environments to block certain WebAssembly functions which +compile bytes from a Response object into WebAssembly code. + +An implementation of HostEnsureCanCompileWasmResponse may complete normally or +abruptly. Any abrupt completions will be propagated to its callers. The default +implementation of HostEnsureCanCompileWasmResponse is to unconditionally return an +empty normal completion. +

Developer-Facing Display Conventions

Browsers, JavaScript engines, and offline tools have common ways of referring to From 87945e967180ceaff9d5591d561d08f4efe069b2 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Thu, 8 Mar 2018 16:13:45 -0800 Subject: [PATCH 11/59] Delete spurious newline --- document/js-api/index.bs | 1 - 1 file changed, 1 deletion(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 993a7a967e..aa47723ea9 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -244,7 +244,6 @@ namespace WebAssembly { Promise<WebAssemblyInstantiatedSource> instantiate( BufferSource bytes, optional object importObject); - Promise<Instance> instantiate( Module moduleObject, optional object importObject); }; From 3eef43ba47ed0dab84aa3d124d4c8cc82d7d46bf Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Fri, 24 Aug 2018 12:51:20 +0200 Subject: [PATCH 12/59] Add table entries for instantiation --- proposals/CSP.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index aaee520e4f..2fb583f93c 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -70,7 +70,9 @@ WebAssembly.validate | yes | yes | yes | yes new WebAssembly.Module | no | yes | yes | yes WebAssembly.compile | no | yes | yes | yes WebAssembly.compileStreaming | no | yes | yes | yes -WebAssembly.instantiate | no | no | yes | yes +new WebAssembly.Instance | ? | ? | ? | ? +WebAssembly.instantiate(WebAssembly.Module, ...) | no | no | yes | yes +WebAssembly.instantiate(BufferSource, ...) | no | no | yes | yes WebAssembly.instantiateStreaming | no | no | yes | yes new WebAssembly.CompileError | yes | yes | yes | yes new WebAssembly.LinkError | yes | yes | yes | yes @@ -126,7 +128,9 @@ WebAssembly.validate | yes new WebAssembly.Module | no WebAssembly.compile | no WebAssembly.compileStreaming | no -WebAssembly.instantiate | no +new WebAssembly.Instance | yes +WebAssembly.instantiate(WebAssembly.Module, ...) | yes +WebAssembly.instantiate(BufferSource, ...) | no WebAssembly.instantiateStreaming | no new WebAssembly.CompileError | yes new WebAssembly.LinkError | yes From 529968a23423d09d556e4bebf487939293a5a501 Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Thu, 13 Sep 2018 15:34:22 +0200 Subject: [PATCH 13/59] Reword paragraph about CSP threat model --- proposals/CSP.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index 6239dca296..4e47978d3a 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -122,11 +122,19 @@ _Risks:_ equivalent to `WebAssembly.instantiate`. ### Recommended Application of CSP -Given the threat model for CSP, operations that load executable code should be -subject to CSP restrictions. This would cover `WebAssembly.instantiate` and -`WebAssembly.instantiateStreaming`. There are risks with `WebAssembly.compile` -and `WebAssembly.compileStreaming`, but these risks are explicitly outside the -CSP threat model. +CSP policies can be used to restrict the construction of `WebAssembly.Module` objects. +Given the threat model for CSP, operations that load Wasm bytes over the network +or create `WebAssembly.Module` objects from raw bytes should be subject to CSP +restrictions. + +Instantiating `WebAssembly.Module` objects is considered safe. +Unlike JavaScript `eval`, WebAssembly is capabilities-based: an instance +may only access the functionality explicitly supplied to it as imports and cannot +access ambient state such as the JavaScript global object. +Protecting the JavaScript-supplied imports to a WebAssembly module is orthogonal +to CSP directives for WebAssembly. +Thus instantiating `WebAssembly.Module` objects need not be subject to CSP +restrictions. ## Behavior of Current Implementations From 60bbf518d9d51b24c09d8edbc1b6885f73312173 Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Mon, 29 Oct 2018 14:00:43 +0100 Subject: [PATCH 14/59] Rename \'wasm-eval\' to \'wasm-unsafe-eval\' --- proposals/CSP.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index 2fb583f93c..dfb68714c5 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -138,7 +138,7 @@ new WebAssembly.Table | yes new WebAssembly.Memory | yes -## Proposed 'wasm-eval' Directive +## Proposed 'wasm-unsafe-eval' Directive WebAssembly compilation is less prone to being spoofed in the way JavaScript is. Further, WebAssembly has an explicitly specified scope, @@ -153,13 +153,13 @@ NOTE: Providing a directive to allow JavaScript eval() without WebAssembly doesn't seem immediately useful, and so has been left out intentionally. We propose: -* Allow the 'wasm-eval' directive under each directive that currently +* Allow the 'wasm-unsafe-eval' directive under each directive that currently supports 'unsafe-eval' (this is currently all directives because directives can defer to each other). * For the `script-src` directive (directly or by reference), - interpret 'wasm-eval' to mean + interpret 'wasm-unsafe-eval' to mean that all WebAssembly operations should be allowed. - (Without allowing eval()). + (Without allowing JavaScript eval()). ## Proposed Origin Bound Permission @@ -188,7 +188,7 @@ Proposed Changes: The desired end state with both of these looks something like this: -Operation | default | unsafe-eval | wasm-eval | unsafe-eval + wasm-eval | w/ SRI ok | w/o SRI bad +Operation | default | unsafe-eval | wasm-unsafe-eval | unsafe-eval + wasm-unsafe-val | w/ SRI ok | w/o SRI bad --- | --- | --- | --- | -- | -- | -- WebAssembly.validate | allow | disallow | allow | allow | N/A | N/A new WebAssembly.Module | allow | allow if from instantiateCompile | allow | allow | allow if from instantiateCompile | disallow if from instantiateCompile From fca6045c2eb74d185d0dae11e50617cf70c1db1e Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Mon, 29 Oct 2018 15:06:28 +0100 Subject: [PATCH 15/59] Remove reference to mimetype hardening --- proposals/CSP.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index 2fb583f93c..fcbb5b4bd8 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -173,12 +173,8 @@ Proposed Changes: * Response.url will be "hardened" to allow it (or it with a taint track bit) to be trusted to carry information regarding the origin of a fetch response. -* An immutable opaque bit mimeTypeWasm will be added to Response to capture - whether the original Response had mime type 'application/wasm'. - * Question: Does this interfere with service worker? * WebAssembly compilation / instantiation requests that would be allowed if they were script src's for non-inline JavaScript - which also have mimeTypeWasm, will also be allowed for WebAssembly. * This applies to hashes, or to origin whitelisting. * This sub-proposal only affects WebAssembly.compileStreaming From 55eae1b86b2ac6c017cf16234ec8786350cb27e5 Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Wed, 31 Oct 2018 15:31:40 +0100 Subject: [PATCH 16/59] Always allow WebAssembly.validate() --- proposals/CSP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index 2fb583f93c..a129f37e94 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -190,12 +190,12 @@ The desired end state with both of these looks something like this: Operation | default | unsafe-eval | wasm-eval | unsafe-eval + wasm-eval | w/ SRI ok | w/o SRI bad --- | --- | --- | --- | -- | -- | -- -WebAssembly.validate | allow | disallow | allow | allow | N/A | N/A new WebAssembly.Module | allow | allow if from instantiateCompile | allow | allow | allow if from instantiateCompile | disallow if from instantiateCompile WebAssembly.compile | allow | disallow | allow | allow | N/A | N/A WebAssembly.compileStreaming | based on SRI | based on SRI | based on SRI | based on SRI | allow | disallow WebAssembly.instantiate | allow | allow if from instantiateCompile | allow | allow | allow if from instantiateCompile | disallow if from instantiateCompile WebAssembly.instantiateStreaming | based on SRI | based on SRI | based on SRI | based on SRI | allow | disallow +WebAssembly.validate | allow | allow | allow | allow | allow | allow new WebAssembly.CompileError | allow | allow | allow | allow | allow | allow new WebAssembly.LinkError | allow | allow | allow | allow | allow | allow new WebAssembly.Table | allow | allow | allow | allow | allow | allow From 86a899f964930844b1f983f036928ef5df8bb7be Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Wed, 31 Oct 2018 16:05:33 +0100 Subject: [PATCH 17/59] Rework final table for clarity --- proposals/CSP.md | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index b235c7f25f..62fac830ab 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -180,22 +180,30 @@ Proposed Changes: * This sub-proposal only affects WebAssembly.compileStreaming and WebAssembly.instatiateStreaming -### Total Behavior +### CSP Policy Application Summary -The desired end state with both of these looks something like this: +The checks performed for web assembly operations is summarized as follows: -Operation | default | unsafe-eval | wasm-unsafe-eval | unsafe-eval + wasm-unsafe-val | w/ SRI ok | w/o SRI bad +Operation | default | no unsafe-eval | with wasm-unsafe-eval | with unsafe-eval and wasm-unsafe-val --- | --- | --- | --- | -- | -- | -- -WebAssembly.validate | allow | disallow | allow | allow | N/A | N/A -new WebAssembly.Module | allow | allow if from instantiateCompile | allow | allow | allow if from instantiateCompile | disallow if from instantiateCompile -WebAssembly.compile | allow | disallow | allow | allow | N/A | N/A -WebAssembly.compileStreaming | based on SRI | based on SRI | based on SRI | based on SRI | allow | disallow -WebAssembly.instantiate | allow | allow if from instantiateCompile | allow | allow | allow if from instantiateCompile | disallow if from instantiateCompile -WebAssembly.instantiateStreaming | based on SRI | based on SRI | based on SRI | based on SRI | allow | disallow -new WebAssembly.CompileError | allow | allow | allow | allow | allow | allow -new WebAssembly.LinkError | allow | allow | allow | allow | allow | allow -new WebAssembly.Table | allow | allow | allow | allow | allow | allow -new WebAssembly.Memory | allow | allow | allow | allow | allow | allow +JavaScript eval | allow | SRI-hash | SRI-hash | allow +new WebAssembly.Module(bytes) | allow | SRI-hash | allow | allow +WebAssembly.compile(bytes) | allow | SRI-hash | allow | allow +WebAssembly.instantiate(bytes, ...) | allow | SRI-hash | allow | allow +WebAssembly.instantiate(module, ...) | allow | allow | allow | allow +WebAssembly.compileStreaming(Response) | allow | script-src | script-src | script-src +WebAssembly.instantiateStreaming(Response, ...) | allow | script-src | script-src | script-src +WebAssembly.validate(bytes) | allow | allow | allow | allow +new WebAssembly.Instance(module) | allow | allow | allow | allow +new WebAssembly.CompileError | allow | allow | allow | allow +new WebAssembly.LinkError | allow | allow | allow | allow +new WebAssembly.Table | allow | allow | allow | allow +new WebAssembly.Memory | allow | allow | allow | allow + +Where SRI-hash means applying sub-resource-integrity checks based on the hash of the supplied bytes, +rejecting the operation if the hash does not match whitelisted hashes, +and script-src means rejecting operations that are not allowed by the CSP +policy's directives for the source of scripts, e.g. script-src restricting origins. ### Examples From 8fd44027ad1c5ca6dd7181b5ff5cc01d77324a03 Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Mon, 12 Nov 2018 15:11:52 +0100 Subject: [PATCH 18/59] Fix table --- proposals/CSP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index 62fac830ab..8d284d20e0 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -185,7 +185,7 @@ Proposed Changes: The checks performed for web assembly operations is summarized as follows: Operation | default | no unsafe-eval | with wasm-unsafe-eval | with unsafe-eval and wasm-unsafe-val ---- | --- | --- | --- | -- | -- | -- +--- | --- | --- | --- | --- JavaScript eval | allow | SRI-hash | SRI-hash | allow new WebAssembly.Module(bytes) | allow | SRI-hash | allow | allow WebAssembly.compile(bytes) | allow | SRI-hash | allow | allow From e822b295af7ea7f9b9b95a93ce00a52f31b4f7e2 Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Tue, 13 Nov 2018 14:02:48 +0100 Subject: [PATCH 19/59] Add note about unsafe-eval implying wasm-unsafe-eval --- proposals/CSP.md | 1 + 1 file changed, 1 insertion(+) diff --git a/proposals/CSP.md b/proposals/CSP.md index 8d284d20e0..5d2127cfaf 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -204,6 +204,7 @@ Where SRI-hash means applying sub-resource-integrity checks based on the hash of rejecting the operation if the hash does not match whitelisted hashes, and script-src means rejecting operations that are not allowed by the CSP policy's directives for the source of scripts, e.g. script-src restricting origins. +Note that `unsafe-eval` effectively *implies* `wasm-unsafe-eval`. ### Examples From ca8a1b3b86b2ea641e9802c3f4e7d3678544b062 Mon Sep 17 00:00:00 2001 From: ANDO Yasushi Date: Wed, 24 Jul 2019 02:07:41 +0900 Subject: [PATCH 20/59] fix typo --- proposals/CSP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index c64c1ebb1a..8203717d76 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -270,7 +270,7 @@ Proposed Changes: The checks performed for web assembly operations is summarized as follows: -Operation | default | no unsafe-eval | with wasm-unsafe-eval | with unsafe-eval and wasm-unsafe-val +Operation | default | no unsafe-eval | with wasm-unsafe-eval | with unsafe-eval and wasm-unsafe-eval --- | --- | --- | --- | --- JavaScript eval | allow | SRI-hash | SRI-hash | allow new WebAssembly.Module(bytes) | allow | SRI-hash | allow | allow From c21513af9ec9df4c2acf99b545aa9b743eea43c4 Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Mon, 10 May 2021 11:03:49 -0700 Subject: [PATCH 21/59] Revised and simplified note --- proposals/CSP.md | 281 +++++++++++++---------------------------------- 1 file changed, 75 insertions(+), 206 deletions(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index 8203717d76..81332d773f 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -1,94 +1,76 @@ # WebAssembly Content Security Policy -This proposal attempts to homogenize existing WebAssembly implementation's -handling of Content Security Policy (CSP). +This note describes a recommendation to the WebAppSec WG to extend Content Security Policy (CSP) to support compiling and executing WebAssembly modules. -It also attempts to extend CSP to better support WebAssemble use cases. +## Background: WebAssembly, Trust and Safety -## Background: CSP Threat Model and Use Cases +In order for a user to experience the benefits of using a particular WebAssembly module there are three (at least) parties that must collaborate: the browser (or other host environment), the publisher (the author of the WebAssembly module) and the user. Each party seeks some form of guarantee from the other parties that allow that party to trust the others. This trust centric modeling allows us to paint a more accurate picture of WebAssembly security. -This section describes the attacks that CSP is meant to protect -against. WebAssembly's handling of CSP should respect this threat model. +### WebAssembly Sandbox -CSP, broadly, allows developers to control what resources can be loaded as part -of a site. These resources can include images, audio, video, or scripts. Loading -untrusted resources can lead to a variety of undesirable outcomes. Malicious -scripts could exfiltrate data from the site. Images could display misleading or -incorrect information. Fetching resources leaks information about the user to -untrusted third parties. +WebAssembly has a sandbox-style security model which focuses on limiting the potential damage a WebAssembly module can do to its host environment. For example, a WebAssembly module is not permitted to access any functions from the host other than those explicitly passed to it via imports. Similarly, a WebAssembly module cannot directly access the evaluation stack; which also limits the potential for attacks based on manipulating return addresses and other important stack data. -While these threats could be protected against in other ways, CSP allows a small -set of security experts to define a comprehensive policy in one place to prevent -accidentally loading untrusted resources into the site. +By imposing this sandbox on the execution of a WebAssembly model, the browser (or other host) gains sufficient trust that browser is willing to permit the WebAssembly code to execute. -### Out of Scope Threats +This does not, however, provide any guarantees that WebAssembly modules compute correct results: it is still possible that an incorrectly programmed module may corrupt data, produce invalid results and be subject to attacks such as SQL injection and even buffer overrun affecting data structures within an application. Since the memory used by a WebAssembly module may be shared via ArrayBuffers these faults may be visible to and affect other WebAssembly and JavaScript modules that also share the same memory. Other memory faults - such as use-after-free and accessing uninitialized memory - are also similarly not protected against by the engine. -* **Bugs in the browser**. We assume correct implementations of image decoders, - script compilers, etc. CSP does not protect against malicious inputs that can, - for example, trigger buffer overflows. -* **Resource exhaustion**. Computation performed by scripts uses memory and CPU - time and can therefore cause a denial of service on the browser. Protecting - against this is one reason site owners use CSP, but denial of service is not a - first order consideration for CSP. Scripts are dangerous not because of their - resource consumption but because of other effects that can cause. +We should also note that a malicious module may be completely safe in terms of the resources from the host that it uses and still cause significant harm to the user. A classic example of this would be a surruptiously loaded crypto-mining WebAssembly module. +a +In addition, the sandbox model does not manage _which_ WebAssembly modules are executed. Controlling which WebAssembly modules are executed is the primary focus of CSP. +### CSP Resource Control -## WebAssembly and CSP +CSP, broadly, allows a publisher to control what resources can be loaded as part +of a site. These resources can include images, audio, video, or scripts. In particular, a suitable CSP should allow the publisher to declare to the host which WebAssembly modules may be executed by the browser on behalf of the user. -A WebAssembly Instance is made up of the code, or Wasm bytes, and an import -object. The import object defines the capabilities of the instance, and -therefore the worst case security behavior. An instance with an empty import -object cannot cause any effects and is therefore safe to run. If it were -possible to vet the import object, it would be safe to create instances and run -from untrusted Wasm code because the behavior of the code would be bounded by -the capabilities of the import object. In practice, vetting an import object is -extremely difficult in JavaScript; it is easy to accidentally give access to the -global object. +It is important to manage this as malicious WebAssembly modules could exfiltrate data from the site. Images could display misleading or +incorrect information. Fetching resources leaks information about the user to +untrusted third parties. -CSP turns the problem around. Assuming unrestricted capabilities, what code is -the developer willing to run on their site? Thus for WebAssembly, CSP will be -used to define what sources for Wasm bytes are trusted to instantiate and run. +Viewed in terms of _trust_ modeling, the CSP allows the content publisher to establish a trust contract with the browser -- and therefore be willing to let the browser execute the publisher's code. It does not, however, address the trust that a user must express when accessing functionality from a WebAssembly module. This is crucially important; however, it is also beyond the scope of this note. -### Summary of WebAssembly APIs and Their Risks +### WebAssembly Execution API -This section introduces the APIs provided by WebAssembly that are relevant to -Content Security Policy. +Executing WebAssembly has several steps. -Executing WebAssembly has several steps. First there are the raw WebAssembly +1. First there are the raw WebAssembly bytes, which typically are loaded using the [fetch -API](https://fetch.spec.whatwg.org/). Next, the bytes are compiled using +API](https://fetch.spec.whatwg.org/). + +1. Next, the bytes are compiled using `WebAssembly.compile` or `WebAssembly.compileStreaming` into a `WebAssembly.Module`. This module is not yet executable, but WebAssembly implementations may choose to translate the WebAssembly code into machine code -at this step (Chrome does this, WebKit does not). Finally, a WebAssembly module +at this step. + +1. Finally, a WebAssembly module is combined with an _import object_ using `WebAssembly.instantiate` to create an `WebAssembly.Instance` object. The import object, broadly, defines the capabilities of the resulting instance, optionally including a `WebAssembly.Memory`, bindings for the WebAssembly function imports, and an -indirect function call table. It is at this point that the WebAssembly code is -actually executable, as the host code can call WebAssembly functions through the -instance's exports. +indirect function call table. + + Note that, via the `start` function, some functionality within a WebAssembly module may start executing at this point. However, for the most part, the host accesses WebAssembly functions through the instance's exports. These steps provide the core of the WebAssembly API, but there are several other methods provided as well. These are summarized below along with their risks that are related to CSP. +### Risk Analysis of WebAssembly API + [**`WebAssembly.validate`**](https://webassembly.github.io/spec/js-api/index.html#dom-webassembly-validate) checks whether the given bytes comprise a valid WebAssembly program. In other words, it checks whether the bytes are syntactically correct and valid according to the WebAssembly type system. -_Risks:_ None. +_Risks:_ Limited to certain denial of service style attacks. Currently the cost of validating a WebAssembly module is linear on the size of the module; however, certain anticipated changes to the WebAssembly type system may change that. [**`new WebAssembly.Module`**](https://webassembly.github.io/spec/js-api/index.html#dom-module-module) synchronously creates a `WebAssembly.Module` from WebAssembly bytes. This is a synchronous version of `WebAssembly.compile`. _Risks:_ many implementations will generate machine code at this step, even -though it is not yet exposed as executable code to the surrounding program. It's -possible that this code be used to build an exploit by taking advantage of -another bug in the implementation. This risk is explicitly out of scope for the -threat model we are working under. +though it is not yet exposed as executable code to the surrounding program. [**`WebAssembly.compile`**](https://webassembly.github.io/spec/js-api/index.html#dom-webassembly-compile) provides a `Promise` that resolves to a `WebAssembly.Module` generated from the @@ -109,8 +91,9 @@ The function returns a `WebAssembly.Instance` that allows executing the WebAssembly code. If WebAssembly bytes are provided, `instantiate` will first perform the steps of `WebAssembly.compile`. -_Risks:_ loads executable code into the running program. This code is confined, -being only able to access objects reachable from the import object. The instance +_Risks:_ loads executable code into the running program and execute any included `start` function. + +As noted above, WebAssembly functions are only able to access objects reachable from the import object. The instance does not have unrestricted access to the JavaScript global object. [**`WebAssembly.instantiateStreaming`**](https://webassembly.github.io/spec/web-api/index.html#dom-webassembly-instantiatestreaming) @@ -120,157 +103,40 @@ creates a `WebAssembly.Instance`. _Risks:_ equivalent to `WebAssembly.instantiate`. -### Recommended Application of CSP - -CSP policies can be used to restrict the construction of `WebAssembly.Module` objects. -Given the threat model for CSP, operations that load Wasm bytes over the network -or create `WebAssembly.Module` objects from raw bytes should be subject to CSP -restrictions. - -Instantiating `WebAssembly.Module` objects is considered safe. -Unlike JavaScript `eval`, WebAssembly is capabilities-based: an instance -may only access the functionality explicitly supplied to it as imports and cannot -access ambient state such as the JavaScript global object. -Protecting the JavaScript-supplied imports to a WebAssembly module is orthogonal -to CSP directives for WebAssembly. -Thus instantiating `WebAssembly.Module` objects need not be subject to CSP -restrictions. - -## Behavior of Current Implementations - -All implementations currently permit all the WebAssembly operations they -support if there is no Content-Security-Policy specified. - -All implementations currently permit all the WebAssembly operations they -support if there is a Content-Security-Policy specified -and `script-src` includes the 'unsafe-eval' directive. - -Implementations vary as to which WebAssembly operations are allowed -if there is a Content-Security-Policy specified and -`script-src` does not include the 'unsafe-eval' directive. -The following table describes which operations are allowed in this case: - -Operation | Chrome | Safari | Firefox | Edge ---- | --- | --- | --- | --- -WebAssembly.validate | yes | yes | yes | yes -new WebAssembly.Module | no | yes | yes | yes -WebAssembly.compile | no | yes | yes | yes -WebAssembly.compileStreaming | no | yes | yes | yes -new WebAssembly.Instance | ? | ? | ? | ? -WebAssembly.instantiate(WebAssembly.Module, ...) | no | no | yes | yes -WebAssembly.instantiate(BufferSource, ...) | no | no | yes | yes -WebAssembly.instantiateStreaming | no | no | yes | yes -new WebAssembly.CompileError | yes | yes | yes | yes -new WebAssembly.LinkError | yes | yes | yes | yes -new WebAssembly.Table | yes | no | yes | yes -new WebAssembly.Memory | yes | no | yes | yes - -The type of exception thrown when one of the above operations is disallowed -also varies by implementation. -This table lists the exception type for each implementation: - -Browser | Thrown if disallowed ---- | -- -Chrome | WebAssembly.CompileError: Wasm code generation disallowed in this context -Safari | EvalError -Firefox | N/A -Edge | ?? - -For references here is how each brower handles eval(): - -Browser | Thrown if disallowed ---- | -- -Chrome | EvalError -Safari | EvalError -Firefox | Disallows script (uncatchable) -Edge | ?? - - -## Proposed Homogenization of Existing Behavior - -Motivating Principles: - -* Be conservative about what is allowed. -* Allow operations which cannot be origin bound within - the current API surface (Chrome's behavior). - * Allow Memory and Table objects, because they are tied to - the current origin, - will be needed when compilation / instantiation is origin bound, - have no parameters allowing an explicit origin. - * Disallow compilation, as it can be used to exercise WebAssembly - code compilation if an injection attack is present. -* Throw an EvalError (Safari's behavior), as this is what both - Chrome and Safari do for eval(). NOTE: Firefox's behavior is even more - conservative, but this might be challenging for others as it is more - strict than for eval(). - -This table describes which operations should be allowed when -there is a Content-Security-Policy specified and -`script-src` does not include the 'unsafe-eval' directive: - -Operation | Result ---- | --- -WebAssembly.validate | yes -new WebAssembly.Module | no -WebAssembly.compile | no -WebAssembly.compileStreaming | no -new WebAssembly.Instance | yes -WebAssembly.instantiate(WebAssembly.Module, ...) | yes -WebAssembly.instantiate(BufferSource, ...) | no -WebAssembly.instantiateStreaming | no -new WebAssembly.CompileError | yes -new WebAssembly.LinkError | yes -new WebAssembly.Table | yes -new WebAssembly.Memory | yes - - -## Proposed 'wasm-unsafe-eval' Directive - -WebAssembly compilation is less prone to being spoofed in the way -JavaScript is. Further, WebAssembly has an explicitly specified scope, -further reducing the likelihood of injection attacks. - -While origin bound / known hash operations are always safer, -it is useful to have a mechanism to allow WebAssembly content -in a CSP policy that would otherwise disallow it, without being -required to also allow JavaScript eval(). - -NOTE: Providing a directive to allow JavaScript eval() without WebAssembly -doesn't seem immediately useful, and so has been left out intentionally. - -We propose: -* Allow the 'wasm-unsafe-eval' directive under each directive that currently - supports 'unsafe-eval' (this is currently all directives because - directives can defer to each other). -* For the `script-src` directive (directly or by reference), - interpret 'wasm-unsafe-eval' to mean - that all WebAssembly operations should be allowed. - (Without allowing JavaScript eval()). - - -## Proposed Origin Bound Permission - -In order to make WebAssembly more useful within the spirit of CSP, -we should permit `Response` objects to carry trusted origin information. -This will allow compilation and instantiation of WebAssembly -in a natural way within a CSP. - -Proposed Changes: -* Response.url will be "hardened" to allow it (or it with a taint track bit) - to be trusted to carry information regarding the origin of a fetch - response. -* WebAssembly compilation / instantiation requests that would - be allowed if they were script src's for non-inline JavaScript - will also be allowed for WebAssembly. - * This applies to hashes, or to origin whitelisting. -* This sub-proposal only affects WebAssembly.compileStreaming - and WebAssembly.instatiateStreaming - -### CSP Policy Application Summary - -The checks performed for web assembly operations is summarized as follows: - -Operation | default | no unsafe-eval | with wasm-unsafe-eval | with unsafe-eval and wasm-unsafe-eval +### Out of Scope Threats + +* **Bugs in the browser**. We assume correct implementations of image decoders, + script compilers, etc. CSP does not protect against malicious inputs that can, + for example, trigger buffer overflows. +* **Resource exhaustion**. Computation performed by scripts uses memory and CPU + time and can therefore cause a denial of service on the browser. Protecting + against this is one reason site owners use CSP, but denial of service is not a + first order consideration for CSP. Scripts are dangerous not because of their + resource consumption but because of other effects that can cause. + +## WebAssembly and CSP + +As noted earlier, CSP allows publishers to control what resources are loaded into a browser from a Web application. This includes resources that are dynamically created as well as those loaded directly. There is no direct equivalent of a `script` element tag for WebAssembly modules; although it is possible that such an feature may be specified in the future. Instead, WebAssembly modules are compiled and instantiated via a JavaScript API. Thus our focus on CSP for WebAssembly is on that API. + +### The `HostEnsureCanCompileWasmBytes` Policy Point + +It is proposed that the above APIs are _gated_ by a policy point: `HostEnsureCanCompileWasmBytes`. (This is sometimes referred to as an _abstract operation_ that must be performed by the host to permit the compilation.) + +#### `HostEnsureCanCompileWasmBytes` + +If `HostEnsureCanCompileWasmBytes` is not enabled, then the `WebAssembly.compile` and `WebAssembly.compileStreaming` functions fail with a `WebAssembly.EvalError??` exception. Otherwise, these API functions return results depending on the internal integrity of the WebAssembly module being compiled. + +### The `wasm-eval` source directive + +We recommend that a new CSP policy directive `wasm-eval` be created. If set in the headers of a page, then the `HostEnsureCanCompileWasmBytes` policy point is enabled; which, in turn, allows the page to load, compile and instantiate WebAssembly code. The details of these abstract operations will be incorporated into a future version of the CSP specification. + +Given the current usage of the CSP policy `unsafe-eval` to gate both JavaScript `eval` and instantiating WebAssembly modules, we propose that that behavior be allowed to continue; but that `wasm-eval` should have no implication for JavaScript loading or evaluation or use of `eval` in JavaScript. NOTE: Providing a directive to allow JavaScript `eval` without WebAssembly doesn't seem immediately useful, and so has been left out intentionally. + +### Proposed Policy Behavior + +This table describes which operations should be allowed when there is a Content-Security-Policy specified: + +Operation | default | no unsafe-eval | with wasm-eval | with unsafe-eval and wasm-eval --- | --- | --- | --- | --- JavaScript eval | allow | SRI-hash | SRI-hash | allow new WebAssembly.Module(bytes) | allow | SRI-hash | allow | allow @@ -290,8 +156,11 @@ Where SRI-hash means applying sub-resource-integrity checks based on the hash of rejecting the operation if the hash does not match whitelisted hashes, and script-src means rejecting operations that are not allowed by the CSP policy's directives for the source of scripts, e.g. script-src restricting origins. -Note that `unsafe-eval` effectively *implies* `wasm-unsafe-eval`. -### Examples +Note that `unsafe-eval` effectively *implies* `wasm-eval`. + +On the event of failure, then an `EvalError` should be thrown by the appropriate JavaScript operation. + +#### Examples ``` Content-Security-Policy: script-src 'self'; From cbf723a3bc36a896d6fb42b99c28e6fb104655a6 Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Tue, 11 May 2021 08:47:33 -0700 Subject: [PATCH 22/59] Update proposals/CSP.md Co-authored-by: Anne van Kesteren --- proposals/CSP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index 81332d773f..d047e3e6cb 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -27,7 +27,7 @@ It is important to manage this as malicious WebAssembly modules could exfiltrate incorrect information. Fetching resources leaks information about the user to untrusted third parties. -Viewed in terms of _trust_ modeling, the CSP allows the content publisher to establish a trust contract with the browser -- and therefore be willing to let the browser execute the publisher's code. It does not, however, address the trust that a user must express when accessing functionality from a WebAssembly module. This is crucially important; however, it is also beyond the scope of this note. +Viewed in terms of _trust_ modeling, CSP allows the content publisher to establish a trust contract with the browser -- and therefore be willing to let the browser execute the publisher's code. It does not, however, address the trust that a user must express when accessing functionality from a WebAssembly module. This is crucially important; however, it is also beyond the scope of this note. ### WebAssembly Execution API From a62b487ef185a354ddc14132a505aa623ddfed2c Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Tue, 11 May 2021 08:47:56 -0700 Subject: [PATCH 23/59] Update proposals/CSP.md Co-authored-by: Anne van Kesteren --- proposals/CSP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index d047e3e6cb..59f9cb0a9e 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -116,7 +116,7 @@ _Risks:_ equivalent to `WebAssembly.instantiate`. ## WebAssembly and CSP -As noted earlier, CSP allows publishers to control what resources are loaded into a browser from a Web application. This includes resources that are dynamically created as well as those loaded directly. There is no direct equivalent of a `script` element tag for WebAssembly modules; although it is possible that such an feature may be specified in the future. Instead, WebAssembly modules are compiled and instantiated via a JavaScript API. Thus our focus on CSP for WebAssembly is on that API. +As noted earlier, CSP allows publishers to control what resources are loaded into a browser from a Web application. This includes resources that are dynamically created as well as those loaded directly. There is no direct equivalent of a `script` element for WebAssembly modules; although it is possible that such an feature may be specified in the future. Instead, WebAssembly modules are compiled and instantiated via a JavaScript API. Thus our focus on CSP for WebAssembly is on that API. ### The `HostEnsureCanCompileWasmBytes` Policy Point From 4ed70b239eea5e48efac0ad395b44796e318c385 Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Tue, 11 May 2021 14:37:56 -0700 Subject: [PATCH 24/59] Changed wasm-eval to wasm-unsafe-eval --- proposals/CSP.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index 59f9cb0a9e..677c84cb39 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -15,7 +15,7 @@ By imposing this sandbox on the execution of a WebAssembly model, the browser (o This does not, however, provide any guarantees that WebAssembly modules compute correct results: it is still possible that an incorrectly programmed module may corrupt data, produce invalid results and be subject to attacks such as SQL injection and even buffer overrun affecting data structures within an application. Since the memory used by a WebAssembly module may be shared via ArrayBuffers these faults may be visible to and affect other WebAssembly and JavaScript modules that also share the same memory. Other memory faults - such as use-after-free and accessing uninitialized memory - are also similarly not protected against by the engine. We should also note that a malicious module may be completely safe in terms of the resources from the host that it uses and still cause significant harm to the user. A classic example of this would be a surruptiously loaded crypto-mining WebAssembly module. -a + In addition, the sandbox model does not manage _which_ WebAssembly modules are executed. Controlling which WebAssembly modules are executed is the primary focus of CSP. ### CSP Resource Control @@ -126,17 +126,17 @@ It is proposed that the above APIs are _gated_ by a policy point: `HostEnsureCan If `HostEnsureCanCompileWasmBytes` is not enabled, then the `WebAssembly.compile` and `WebAssembly.compileStreaming` functions fail with a `WebAssembly.EvalError??` exception. Otherwise, these API functions return results depending on the internal integrity of the WebAssembly module being compiled. -### The `wasm-eval` source directive +### The `wasm-unsafe-eval` source directive -We recommend that a new CSP policy directive `wasm-eval` be created. If set in the headers of a page, then the `HostEnsureCanCompileWasmBytes` policy point is enabled; which, in turn, allows the page to load, compile and instantiate WebAssembly code. The details of these abstract operations will be incorporated into a future version of the CSP specification. +We recommend that a new CSP policy directive `wasm-unsafe-eval` be created. If set in the headers of a page, then the `HostEnsureCanCompileWasmBytes` policy point is enabled; which, in turn, allows the page to load, compile and instantiate WebAssembly code. The details of these abstract operations will be incorporated into a future version of the CSP specification. -Given the current usage of the CSP policy `unsafe-eval` to gate both JavaScript `eval` and instantiating WebAssembly modules, we propose that that behavior be allowed to continue; but that `wasm-eval` should have no implication for JavaScript loading or evaluation or use of `eval` in JavaScript. NOTE: Providing a directive to allow JavaScript `eval` without WebAssembly doesn't seem immediately useful, and so has been left out intentionally. +Given the current usage of the CSP policy `unsafe-eval` to gate both JavaScript `eval` and instantiating WebAssembly modules, we propose that that behavior be allowed to continue; but that `wasm-unsafe-eval` should have no implication for JavaScript loading or evaluation or use of `eval` in JavaScript. NOTE: Providing a directive to allow JavaScript `eval` without WebAssembly doesn't seem immediately useful, and so has been left out intentionally. ### Proposed Policy Behavior This table describes which operations should be allowed when there is a Content-Security-Policy specified: -Operation | default | no unsafe-eval | with wasm-eval | with unsafe-eval and wasm-eval +Operation | default | no unsafe-eval | with wasm-unsafe-eval | with unsafe-eval and wasm-unsafe-eval --- | --- | --- | --- | --- JavaScript eval | allow | SRI-hash | SRI-hash | allow new WebAssembly.Module(bytes) | allow | SRI-hash | allow | allow @@ -156,7 +156,7 @@ Where SRI-hash means applying sub-resource-integrity checks based on the hash of rejecting the operation if the hash does not match whitelisted hashes, and script-src means rejecting operations that are not allowed by the CSP policy's directives for the source of scripts, e.g. script-src restricting origins. -Note that `unsafe-eval` effectively *implies* `wasm-eval`. +Note that `unsafe-eval` effectively *implies* `wasm-unsafe-eval`. On the event of failure, then an `EvalError` should be thrown by the appropriate JavaScript operation. From 55a48c33c5c4ae16ad8ed048f8b2ffae5b52b03f Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Tue, 11 May 2021 14:46:46 -0700 Subject: [PATCH 25/59] Fixed error exception type when failing to compile Also adjusted some of the examples --- proposals/CSP.md | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index 677c84cb39..005db02014 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -124,7 +124,7 @@ It is proposed that the above APIs are _gated_ by a policy point: `HostEnsureCan #### `HostEnsureCanCompileWasmBytes` -If `HostEnsureCanCompileWasmBytes` is not enabled, then the `WebAssembly.compile` and `WebAssembly.compileStreaming` functions fail with a `WebAssembly.EvalError??` exception. Otherwise, these API functions return results depending on the internal integrity of the WebAssembly module being compiled. +If `HostEnsureCanCompileWasmBytes` is not enabled, then the `WebAssembly.compile` and `WebAssembly.compileStreaming` functions fail with a `WebAssembly.CompileError` exception. Otherwise, these API functions return results depending on the internal integrity of the WebAssembly module being compiled. ### The `wasm-unsafe-eval` source directive @@ -158,15 +158,15 @@ and script-src means rejecting operations that are not allowed by the CSP policy's directives for the source of scripts, e.g. script-src restricting origins. Note that `unsafe-eval` effectively *implies* `wasm-unsafe-eval`. -On the event of failure, then an `EvalError` should be thrown by the appropriate JavaScript operation. +On the event of failure, then an `CompileError` should be thrown by the appropriate JavaScript operation. #### Examples ``` Content-Security-Policy: script-src 'self'; -WebAssembly.compileStreaming(fetch('/foo.wasm')); // OK -WebAssembly.instantiateStreaming(fetch('/foo.wasm')); // OK +WebAssembly.compileStreaming(fetch('/foo.wasm')); // BAD: wasm-unsafe-eval compile error +WebAssembly.instantiateStreaming(fetch('/foo.wasm')); // BAD: wasm-unsafe-eval compile error WebAssembly.compileStreaming(fetch('/foo.js')); // BAD: mime type WebAssembly.instantiateStreaming(fetch('/foo.js')); // BAD: mime type WebAssembly.compileStreaming(fetch('http://yo.com/foo.wasm')); // BAD: cross origin @@ -174,15 +174,8 @@ WebAssembly.instantiateStreaming(fetch('http://yo.com/foo.wasm')); // BAD: cross ``` ``` -Content-Security-Policy: script-src http://yo.com; +Content-Security-Policy: script-src http://yo.com 'wasm-unsafe-eval'; WebAssembly.compileStreaming(fetch('http://yo.com/foo.wasm')); // OK WebAssembly.instantiateStreaming(fetch('http://yo.com/foo.wasm')); // OK ``` - -``` -Content-Security-Policy: script-src 'sha256-123...456'; - -WebAssembly.compileStreaming(fetch('http://baz.com/hash123..456.wasm')); // OK -WebAssembly.instantiateStreaming(fetch('http://baz.com/hash123..456.wasm')); // OK -``` From afddc8813163c857c0e3043ed2d5b84a5418796c Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Wed, 12 May 2021 08:52:34 -0700 Subject: [PATCH 26/59] Fix typo --- proposals/CSP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index 005db02014..a3c902ddf3 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -158,7 +158,7 @@ and script-src means rejecting operations that are not allowed by the CSP policy's directives for the source of scripts, e.g. script-src restricting origins. Note that `unsafe-eval` effectively *implies* `wasm-unsafe-eval`. -On the event of failure, then an `CompileError` should be thrown by the appropriate JavaScript operation. +On the event of failure, then a `CompileError` should be thrown by the appropriate JavaScript operation. #### Examples From 2081326b67e162bce454780b84c68a92494af114 Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Tue, 20 Jul 2021 12:45:55 -0700 Subject: [PATCH 27/59] Refactored explainer to use regular script-src for streaming --- proposals/CSP.md | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index a3c902ddf3..8bcdd85b4d 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -132,19 +132,27 @@ We recommend that a new CSP policy directive `wasm-unsafe-eval` be created. If s Given the current usage of the CSP policy `unsafe-eval` to gate both JavaScript `eval` and instantiating WebAssembly modules, we propose that that behavior be allowed to continue; but that `wasm-unsafe-eval` should have no implication for JavaScript loading or evaluation or use of `eval` in JavaScript. NOTE: Providing a directive to allow JavaScript `eval` without WebAssembly doesn't seem immediately useful, and so has been left out intentionally. +### Using existing CSP script-src policies + +While `WebAssembly.compile` and `WebAssembly.instantiate` take arrays of bytes to produce executable code, `WebAssembly.compileStreaming` and `WebAssembly.intantiateStreaming` depend on a `Response` object. One characteristic of the `Response` object is that it has access to the URL of the original request. + +We recommend that this URL may be vetted by the `script-src` CSP policy associated with the _container_ (typically either an IFrame or the page executing the JavaScript call to `compileStreaming` or `instantiateStreaming` APIs). + +In effect, the policy would be that if a source URL is permitted by the `script-src` CSP policy then a WebAssembly module loaded from that source (via a streaming API) would be permitted to execute _without any additional CSP policy tokens_. + ### Proposed Policy Behavior This table describes which operations should be allowed when there is a Content-Security-Policy specified: -Operation | default | no unsafe-eval | with wasm-unsafe-eval | with unsafe-eval and wasm-unsafe-eval +Operation | default | with unsafe-eval | with wasm-unsafe-eval | with active script-src policy --- | --- | --- | --- | --- -JavaScript eval | allow | SRI-hash | SRI-hash | allow -new WebAssembly.Module(bytes) | allow | SRI-hash | allow | allow -WebAssembly.compile(bytes) | allow | SRI-hash | allow | allow -WebAssembly.instantiate(bytes, ...) | allow | SRI-hash | allow | allow +JavaScript eval | allow | allow | not allowed | script-src +new WebAssembly.Module(bytes) | allow | allow | allow | not allowed +WebAssembly.compile(bytes) | allow | allow | allow | not allowed +WebAssembly.instantiate(bytes, ...) | allow | allow | allow | not allowed WebAssembly.instantiate(module, ...) | allow | allow | allow | allow -WebAssembly.compileStreaming(Response) | allow | script-src | script-src | script-src -WebAssembly.instantiateStreaming(Response, ...) | allow | script-src | script-src | script-src +WebAssembly.compileStreaming(Response) | allow | allow | allow | script-src +WebAssembly.instantiateStreaming(Response, ...) | allow | allow | allow | script-src WebAssembly.validate(bytes) | allow | allow | allow | allow new WebAssembly.Instance(module) | allow | allow | allow | allow new WebAssembly.CompileError | allow | allow | allow | allow @@ -152,12 +160,12 @@ new WebAssembly.LinkError | allow | allow | allow | allow new WebAssembly.Table | allow | allow | allow | allow new WebAssembly.Memory | allow | allow | allow | allow -Where SRI-hash means applying sub-resource-integrity checks based on the hash of the supplied bytes, -rejecting the operation if the hash does not match whitelisted hashes, -and script-src means rejecting operations that are not allowed by the CSP +Where script-src means rejecting operations that are not allowed by the CSP policy's directives for the source of scripts, e.g. script-src restricting origins. Note that `unsafe-eval` effectively *implies* `wasm-unsafe-eval`. +Note that some of these operations (`WebAssembly.instantiate(Module)` and `new WebAssembly.Instance(module)`) are effectively gated by the requirement to construct modules, i.e., these operations are dependent on whether `WebAssembly.compile(bytes)` or `WebAssembly.compileStreaming(Response)` are allowed. + On the event of failure, then a `CompileError` should be thrown by the appropriate JavaScript operation. #### Examples @@ -174,7 +182,14 @@ WebAssembly.instantiateStreaming(fetch('http://yo.com/foo.wasm')); // BAD: cross ``` ``` -Content-Security-Policy: script-src http://yo.com 'wasm-unsafe-eval'; +Content-Security-Policy: script-src 'wasm-unsafe-eval'; + +WebAssembly.compileStreaming(fetch('http://example.com/foo.wasm')); // OK +WebAssembly.instantiateStreaming(fetch('http://yo.com/foo.wasm')); // OK +``` + +``` +Content-Security-Policy: script-src http://yo.com; WebAssembly.compileStreaming(fetch('http://yo.com/foo.wasm')); // OK WebAssembly.instantiateStreaming(fetch('http://yo.com/foo.wasm')); // OK From 57ed6202af688fa00850c91dadb7f9a41b48655e Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Tue, 20 Jul 2021 14:12:10 -0700 Subject: [PATCH 28/59] Slight tweak explaining streaming extension --- proposals/CSP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index 8bcdd85b4d..56fbba8e14 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -162,7 +162,7 @@ new WebAssembly.Memory | allow | allow | allow | allow Where script-src means rejecting operations that are not allowed by the CSP policy's directives for the source of scripts, e.g. script-src restricting origins. -Note that `unsafe-eval` effectively *implies* `wasm-unsafe-eval`. +Note that `unsafe-eval` effectively *implies* `wasm-unsafe-eval`; this is, in part, to ensure continued behavior from the current status where `unsafe-eval` is used in order to ensure execution of WebAssembly code. Similarly, apply regular `script-src` policy to WebAssembly is an extension of the existing semantics for `script-src` to a new domain (WebAssembly in addition to JavaScript execution). Note that some of these operations (`WebAssembly.instantiate(Module)` and `new WebAssembly.Instance(module)`) are effectively gated by the requirement to construct modules, i.e., these operations are dependent on whether `WebAssembly.compile(bytes)` or `WebAssembly.compileStreaming(Response)` are allowed. From b0e8b1effde0501aa986401e3444b9dfda6bcdcc Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Tue, 20 Jul 2021 14:12:10 -0700 Subject: [PATCH 29/59] Slight tweak explaining streaming extension --- proposals/CSP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index 8bcdd85b4d..9d8280aa2d 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -162,7 +162,7 @@ new WebAssembly.Memory | allow | allow | allow | allow Where script-src means rejecting operations that are not allowed by the CSP policy's directives for the source of scripts, e.g. script-src restricting origins. -Note that `unsafe-eval` effectively *implies* `wasm-unsafe-eval`. +Note that `unsafe-eval` effectively *implies* `wasm-unsafe-eval`; this is, in part, to ensure continued behavior from the current status where `unsafe-eval` is used in order to ensure execution of WebAssembly code. Similarly, applying regular `script-src` policy to WebAssembly is an extension of the existing semantics for `script-src` to a new domain (WebAssembly in addition to JavaScript execution). Note that some of these operations (`WebAssembly.instantiate(Module)` and `new WebAssembly.Instance(module)`) are effectively gated by the requirement to construct modules, i.e., these operations are dependent on whether `WebAssembly.compile(bytes)` or `WebAssembly.compileStreaming(Response)` are allowed. From 3c888abc80cd132783c0c6ddbf8203282982265f Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Thu, 26 Aug 2021 13:17:54 -0700 Subject: [PATCH 30/59] Modified handling of compileStreaming also aligned with proposal for CSP spec itself --- document/web-api/index.bs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/document/web-api/index.bs b/document/web-api/index.bs index 2342c19fc5..9085eb5cfd 100644 --- a/document/web-api/index.bs +++ b/document/web-api/index.bs @@ -93,13 +93,15 @@ The instantiateStreaming(source, importObject) To compile a potential WebAssembly response with a promise of a {{Response}} |source|, perform the following steps: -Note: This algorithm accepts a {{Response}} object, or a - promise for one, and compiles and instantiates the resulting bytes of the response. This compilation - can be performed in the background and in a streaming manner. If the {{Response}} is not - [=CORS-same-origin=], does not represent an [=ok status=], or does not match the - `` `application/wasm` `` MIME type, the returned promise will be rejected with a {{TypeError}}; if - compilation or instantiation fails, the returned promise will be rejected with a - {{CompileError}} or other relevant error type, depending on the cause of failure. +Note: This algorithm accepts a {{Response}} object, or a promise for one, and + compiles and instantiates the resulting bytes of the response. This + compilation can be performed in the background and in a streaming manner. If + the {{Response}} is not [=CORS-same-origin=], does not represent an [=ok + status=], does not comply with CSP `script-src` policy, or does not match + the `` `application/wasm` `` MIME type, the returned promise will be + rejected with a {{TypeError}}; if compilation or instantiation fails, the + returned promise will be rejected with a {{CompileError}} or other relevant + error type, depending on the cause of failure. 1. Let |returnValue| be [=a new promise=] @@ -111,6 +113,7 @@ Note: This algorithm accepts a {{Response}} object, or a Note: extra parameters are not allowed, including the empty `` `application/wasm;` ``. 4. If |response| is not [=CORS-same-origin=], [=reject=] |returnValue| with a {{TypeError}} and abort these substeps. + 1. If |response|'s [=url=] does not 1. If |response|'s [=response/status=] is not an [=ok status=], [=reject=] |returnValue| with a {{TypeError}} and abort these substeps. 1. Perform [$HostEnsureCanCompileWasmResponse(response)$] 1. [=Consume body|consume=] |response|'s body as an {{ArrayBuffer}}, and let |bodyPromise| be the result. From 07af5944976317a2c48649bd8906e7b8cc44bbbe Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Mon, 30 Aug 2021 14:44:55 -0700 Subject: [PATCH 31/59] Removed funny dangling entry --- document/web-api/index.bs | 1 - 1 file changed, 1 deletion(-) diff --git a/document/web-api/index.bs b/document/web-api/index.bs index 9085eb5cfd..981feb9187 100644 --- a/document/web-api/index.bs +++ b/document/web-api/index.bs @@ -113,7 +113,6 @@ Note: This algorithm accepts a {{Response}} object, or a promise for one, and Note: extra parameters are not allowed, including the empty `` `application/wasm;` ``. 4. If |response| is not [=CORS-same-origin=], [=reject=] |returnValue| with a {{TypeError}} and abort these substeps. - 1. If |response|'s [=url=] does not 1. If |response|'s [=response/status=] is not an [=ok status=], [=reject=] |returnValue| with a {{TypeError}} and abort these substeps. 1. Perform [$HostEnsureCanCompileWasmResponse(response)$] 1. [=Consume body|consume=] |response|'s body as an {{ArrayBuffer}}, and let |bodyPromise| be the result. From 3d3d959f47ae409d2ac273945e2109366dd41b84 Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Mon, 30 Aug 2021 14:48:44 -0700 Subject: [PATCH 32/59] Remove reference to iframe --- proposals/CSP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index 9d8280aa2d..2fc4342df6 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -136,7 +136,7 @@ Given the current usage of the CSP policy `unsafe-eval` to gate both JavaScript While `WebAssembly.compile` and `WebAssembly.instantiate` take arrays of bytes to produce executable code, `WebAssembly.compileStreaming` and `WebAssembly.intantiateStreaming` depend on a `Response` object. One characteristic of the `Response` object is that it has access to the URL of the original request. -We recommend that this URL may be vetted by the `script-src` CSP policy associated with the _container_ (typically either an IFrame or the page executing the JavaScript call to `compileStreaming` or `instantiateStreaming` APIs). +We recommend that this URL may be vetted by the `script-src` CSP policy associated with the _container_ (typically the page executing the JavaScript call to `compileStreaming` or `instantiateStreaming` APIs). In effect, the policy would be that if a source URL is permitted by the `script-src` CSP policy then a WebAssembly module loaded from that source (via a streaming API) would be permitted to execute _without any additional CSP policy tokens_. From e3977ba46d540c5ae6e628626e70c8d95ce93f9a Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Tue, 31 Aug 2021 09:10:35 -0700 Subject: [PATCH 33/59] Update proposals/CSP.md Co-authored-by: Anne van Kesteren --- proposals/CSP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index 2fc4342df6..32c5201bcc 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -134,7 +134,7 @@ Given the current usage of the CSP policy `unsafe-eval` to gate both JavaScript ### Using existing CSP script-src policies -While `WebAssembly.compile` and `WebAssembly.instantiate` take arrays of bytes to produce executable code, `WebAssembly.compileStreaming` and `WebAssembly.intantiateStreaming` depend on a `Response` object. One characteristic of the `Response` object is that it has access to the URL of the original request. +While `WebAssembly.compile` and `WebAssembly.instantiate` take arrays of bytes to produce executable code, `WebAssembly.compileStreaming` and `WebAssembly.intantiateStreaming` take a `Response` object. One characteristic of the `Response` object is that it has access to the URL of the original request. We recommend that this URL may be vetted by the `script-src` CSP policy associated with the _container_ (typically the page executing the JavaScript call to `compileStreaming` or `instantiateStreaming` APIs). From d89c8bc0cdde497d6e63dc7d63ee65a361fe42c9 Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Thu, 9 Sep 2021 14:46:47 -0700 Subject: [PATCH 34/59] Removed text relating to extending script-src to include wasm Removed examples & table as they seemed redundant now --- proposals/CSP.md | 63 +++++++++--------------------------------------- 1 file changed, 12 insertions(+), 51 deletions(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index 32c5201bcc..5ae224df4f 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -132,65 +132,26 @@ We recommend that a new CSP policy directive `wasm-unsafe-eval` be created. If s Given the current usage of the CSP policy `unsafe-eval` to gate both JavaScript `eval` and instantiating WebAssembly modules, we propose that that behavior be allowed to continue; but that `wasm-unsafe-eval` should have no implication for JavaScript loading or evaluation or use of `eval` in JavaScript. NOTE: Providing a directive to allow JavaScript `eval` without WebAssembly doesn't seem immediately useful, and so has been left out intentionally. -### Using existing CSP script-src policies - -While `WebAssembly.compile` and `WebAssembly.instantiate` take arrays of bytes to produce executable code, `WebAssembly.compileStreaming` and `WebAssembly.intantiateStreaming` take a `Response` object. One characteristic of the `Response` object is that it has access to the URL of the original request. - -We recommend that this URL may be vetted by the `script-src` CSP policy associated with the _container_ (typically the page executing the JavaScript call to `compileStreaming` or `instantiateStreaming` APIs). - -In effect, the policy would be that if a source URL is permitted by the `script-src` CSP policy then a WebAssembly module loaded from that source (via a streaming API) would be permitted to execute _without any additional CSP policy tokens_. +#### Proposed Policy Behavior -### Proposed Policy Behavior +With the `wasm-unsafe-eval` source, there are two options for managing WebAssembly execution: `unsafe-eval` and `wasm-unsafe-eval`. The former is primarily intended to govern JavaScript execution -- specifically those JS features that can be used to construct programs from text. However, it has been extended to allow WebAssembly execution. The second is a more targeted source keyword that only applies to WebAssembly. -This table describes which operations should be allowed when there is a Content-Security-Policy specified: +* If the `unsafe-eval` source keyword is used, then this overrides any occurence of `wasm-unsafe-eval` in the CSP policy. -Operation | default | with unsafe-eval | with wasm-unsafe-eval | with active script-src policy ---- | --- | --- | --- | --- -JavaScript eval | allow | allow | not allowed | script-src -new WebAssembly.Module(bytes) | allow | allow | allow | not allowed -WebAssembly.compile(bytes) | allow | allow | allow | not allowed -WebAssembly.instantiate(bytes, ...) | allow | allow | allow | not allowed -WebAssembly.instantiate(module, ...) | allow | allow | allow | allow -WebAssembly.compileStreaming(Response) | allow | allow | allow | script-src -WebAssembly.instantiateStreaming(Response, ...) | allow | allow | allow | script-src -WebAssembly.validate(bytes) | allow | allow | allow | allow -new WebAssembly.Instance(module) | allow | allow | allow | allow -new WebAssembly.CompileError | allow | allow | allow | allow -new WebAssembly.LinkError | allow | allow | allow | allow -new WebAssembly.Table | allow | allow | allow | allow -new WebAssembly.Memory | allow | allow | allow | allow +* If the `wasm-unsafe-eval` source keyword is used, and the `unsafe-eval` keyword is not present, then WebAssembly modules may be compiled and instantiated. -Where script-src means rejecting operations that are not allowed by the CSP -policy's directives for the source of scripts, e.g. script-src restricting origins. -Note that `unsafe-eval` effectively *implies* `wasm-unsafe-eval`; this is, in part, to ensure continued behavior from the current status where `unsafe-eval` is used in order to ensure execution of WebAssembly code. Similarly, applying regular `script-src` policy to WebAssembly is an extension of the existing semantics for `script-src` to a new domain (WebAssembly in addition to JavaScript execution). + One advantage of this is that a website can permit WebAssembly modules to be used without also enabling JavaScript's `eval` keyword. -Note that some of these operations (`WebAssembly.instantiate(Module)` and `new WebAssembly.Instance(module)`) are effectively gated by the requirement to construct modules, i.e., these operations are dependent on whether `WebAssembly.compile(bytes)` or `WebAssembly.compileStreaming(Response)` are allowed. +On the event of failure, then a `CompileError` should be thrown by the `WebAssembly.compile` and related API calls. -On the event of failure, then a `CompileError` should be thrown by the appropriate JavaScript operation. - -#### Examples - -``` -Content-Security-Policy: script-src 'self'; +### Using existing CSP script-src policies -WebAssembly.compileStreaming(fetch('/foo.wasm')); // BAD: wasm-unsafe-eval compile error -WebAssembly.instantiateStreaming(fetch('/foo.wasm')); // BAD: wasm-unsafe-eval compile error -WebAssembly.compileStreaming(fetch('/foo.js')); // BAD: mime type -WebAssembly.instantiateStreaming(fetch('/foo.js')); // BAD: mime type -WebAssembly.compileStreaming(fetch('http://yo.com/foo.wasm')); // BAD: cross origin -WebAssembly.instantiateStreaming(fetch('http://yo.com/foo.wasm')); // BAD: cross origin -``` +Currently, WebAssembly modules are anomolous within the Web platform because there is no specific HTML element tag that references WebAssembly modules. It is reasonable to suggest that the existing `script` tag may one day be extended to also include WebAssembly modules. In that event, it is also reasonable to consider the use of the CSP `script-src` source keyword to include WebAssembly as well as JavaScript. -``` -Content-Security-Policy: script-src 'wasm-unsafe-eval'; +However, it would not be wise to extend the scope of CSP's `script-src` source in this way. The reasons for this are that it could break existing websites and that the specific rules for `script-src` are too tailored to the requirements of JavaScript. -WebAssembly.compileStreaming(fetch('http://example.com/foo.wasm')); // OK -WebAssembly.instantiateStreaming(fetch('http://yo.com/foo.wasm')); // OK -``` +* Extending `script-src` to include WebAssembly has the potential to compromise a website that currently uses a CSP policy for JavaScript that was not intended to support WebAssembly. -``` -Content-Security-Policy: script-src http://yo.com; +* Using a _white list_ approach for allowable domains to source executable can be shown to be difficult to manage in practice. This is especially true for JavaScript, but is also true for WebAssembly. -WebAssembly.compileStreaming(fetch('http://yo.com/foo.wasm')); // OK -WebAssembly.instantiateStreaming(fetch('http://yo.com/foo.wasm')); // OK -``` + * The primary issue with white listing a domain is that it allows _all_ code from that domain. However, many domains -- such as CDNs -- host many code modules; many more than owners of websites can reasonably be aware of. From 097b397b9a129bd5cfe2e22f14fe22f7a44d9d25 Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Fri, 10 Sep 2021 08:59:51 -0700 Subject: [PATCH 35/59] Update proposals/CSP.md Co-authored-by: Anne van Kesteren --- proposals/CSP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index 5ae224df4f..88eb504b74 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -146,7 +146,7 @@ On the event of failure, then a `CompileError` should be thrown by the `WebAssem ### Using existing CSP script-src policies -Currently, WebAssembly modules are anomolous within the Web platform because there is no specific HTML element tag that references WebAssembly modules. It is reasonable to suggest that the existing `script` tag may one day be extended to also include WebAssembly modules. In that event, it is also reasonable to consider the use of the CSP `script-src` source keyword to include WebAssembly as well as JavaScript. +Currently, WebAssembly modules are anomolous within the Web platform because there is no specific HTML element that references WebAssembly modules. It is reasonable to suggest that the existing `script` element may one day be extended to also include WebAssembly modules. In that event, it is also reasonable to consider the use of the CSP `script-src` source keyword to include WebAssembly as well as JavaScript. However, it would not be wise to extend the scope of CSP's `script-src` source in this way. The reasons for this are that it could break existing websites and that the specific rules for `script-src` are too tailored to the requirements of JavaScript. From a43fa62c81b95681ee4ddcbfc2149a1522525044 Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Mon, 18 Oct 2021 02:00:22 -0700 Subject: [PATCH 36/59] Remove reference to Response CSP policy algorithm There's now a single CSP abstract operation: HostEnsureCanCompileWasmBytes. Also removed the bytes argument to this operation (since CSP spec does not require the bytes to be compiled). --- document/js-api/index.bs | 2 +- document/web-api/index.bs | 2 +- proposals/CSP.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index aa47723ea9..ae74ed4da7 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -303,7 +303,7 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
The compile(bytes) method, when invoked, performs the following steps: 1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|. - 1. Perform [$HostEnsureCanCompileWasmBytes(bytes)|HostEnsureCanCompileWasmBytes(stableBytes)$] + 1. Perform [$HostEnsureCanCompileWasmBytes()|HostEnsureCanCompileWasmBytes()$] 1. Let |promise| be [=a new promise=]. 1. [=Asynchronously compile a WebAssembly module=] from |stableBytes| with |promise|. 1. Return |promise|. diff --git a/document/web-api/index.bs b/document/web-api/index.bs index 981feb9187..89bfa02d69 100644 --- a/document/web-api/index.bs +++ b/document/web-api/index.bs @@ -114,7 +114,7 @@ Note: This algorithm accepts a {{Response}} object, or a promise for one, and 4. If |response| is not [=CORS-same-origin=], [=reject=] |returnValue| with a {{TypeError}} and abort these substeps. 1. If |response|'s [=response/status=] is not an [=ok status=], [=reject=] |returnValue| with a {{TypeError}} and abort these substeps. - 1. Perform [$HostEnsureCanCompileWasmResponse(response)$] + 1. Perform [$HostEnsureCanCompileWasmBytes()$] 1. [=Consume body|consume=] |response|'s body as an {{ArrayBuffer}}, and let |bodyPromise| be the result. Note: Although it is specified here that the response is consumed entirely before compilation proceeds, that is purely for ease of specification; implementations are likely to instead perform processing in a streaming fashion. The different is unobservable, and thus the simpler model is specified. diff --git a/proposals/CSP.md b/proposals/CSP.md index 88eb504b74..2db7ab5fb9 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -128,7 +128,7 @@ If `HostEnsureCanCompileWasmBytes` is not enabled, then the `WebAssembly.compile ### The `wasm-unsafe-eval` source directive -We recommend that a new CSP policy directive `wasm-unsafe-eval` be created. If set in the headers of a page, then the `HostEnsureCanCompileWasmBytes` policy point is enabled; which, in turn, allows the page to load, compile and instantiate WebAssembly code. The details of these abstract operations will be incorporated into a future version of the CSP specification. +We recommend that a new CSP policy directive `wasm-unsafe-eval` be created. If set in the headers of a page, then the `HostEnsureCanCompileWasmBytes` policy point is enabled; which, in turn, allows the page to load, compile and instantiate WebAssembly code. This would apply to both the inline APIs (`WebAssembly.compile` etc.) and the streaming APIs (`WebAssembly.compileStreaming` et el.) The details of these abstract operations will be incorporated into a future version of the CSP specification. Given the current usage of the CSP policy `unsafe-eval` to gate both JavaScript `eval` and instantiating WebAssembly modules, we propose that that behavior be allowed to continue; but that `wasm-unsafe-eval` should have no implication for JavaScript loading or evaluation or use of `eval` in JavaScript. NOTE: Providing a directive to allow JavaScript `eval` without WebAssembly doesn't seem immediately useful, and so has been left out intentionally. From 76c7781df7c20ad85cfc625ca604d07f04a5a11b Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Thu, 24 Mar 2022 16:45:05 -0700 Subject: [PATCH 37/59] Fixed up bikeshed errors --- document/js-api/index.bs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 04a2b9c41c..e070a3ed0b 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -188,6 +188,10 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df urlPrefix: https://heycam.github.io/webidl/; spec: WebIDL type: dfn text: create a namespace object; url: create-a-namespace-object + +spec: webappsec-csp; urlPrefix: https://w3c.github.io/webappsec-csp/ + type: method + text: EnsureCSPDoesNotBlockWasmByteCompilation; url: #can-compile-wasm-bytes diff --git a/document/js-api/index.bs b/document/js-api/index.bs index e070a3ed0b..2b118bdeda 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -3,8 +3,8 @@ Title: WebAssembly JavaScript Interface Shortname: wasm-js-api Group: wasm Status: ED -Level: 1 -TR: https://www.w3.org/TR/wasm-js-api-1/ +Level: 2 +TR: https://www.w3.org/TR/wasm-js-api-2/ ED: https://webassembly.github.io/spec/js-api/ Editor: Ms2ger, Igalia Repository: WebAssembly/spec diff --git a/document/web-api/index.bs b/document/web-api/index.bs index ccf40fa144..db6ecaa8c9 100644 --- a/document/web-api/index.bs +++ b/document/web-api/index.bs @@ -3,8 +3,8 @@ Title: WebAssembly Web API Shortname: wasm-web-api Group: wasm Status: ED -Level: 1 -TR: https://www.w3.org/TR/wasm-web-api-1/ +Level: 2 +TR: https://www.w3.org/TR/wasm-web-api-2/ ED: https://webassembly.github.io/spec/web-api/ Editor: Ms2ger, Igalia Repository: WebAssembly/spec diff --git a/interpreter/main/main.ml b/interpreter/main/main.ml index 91b91018fe..898bdef1dc 100644 --- a/interpreter/main/main.ml +++ b/interpreter/main/main.ml @@ -1,5 +1,5 @@ let name = "wasm" -let version = "1.1" +let version = "2.0" let configure () = Import.register (Utf8.decode "spectest") Spectest.lookup; From 7bcf3197602ccdce5bfb38174453927ae79f7d3d Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Thu, 8 Mar 2018 15:06:34 -0800 Subject: [PATCH 45/59] Starting to define abstract operation hooks --- document/js-api/index.bs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 2b118bdeda..4451ddf6cc 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -290,6 +290,7 @@ namespace WebAssembly { Promise<WebAssemblyInstantiatedSource> instantiate( BufferSource bytes, optional object importObject); + Promise<Instance> instantiate( Module moduleObject, optional object importObject); }; @@ -592,6 +593,7 @@ interface Module { The Module(|bytes|) constructor, when invoked, performs the follwing steps: 1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|. + 1. Perform [$HostEnsureCanCompileWasmBytes()$] 1. [=Compile a WebAssembly module|Compile the WebAssembly module=] |stableBytes| and store the result as |module|. 1. If |module| is [=error=], throw a {{CompileError}} exception. 1. Set **this**.\[[Module]] to |module|. @@ -1205,6 +1207,19 @@ Note: ECMAScript doesn't specify any sort of behavior on out-of-memory condition See [Issue 879](https://github.com/WebAssembly/spec/issues/879) for further discussion.
+

Implementation-defined Operations

+ +

HostEnsureCanCompileWasmBytes()

+ +HostEnsureCanCompileWasmBytes is an implementation-defined abstract operation +that allows host environments to block certain WebAssembly functions which +compile bytes into WebAssembly code. + +An implementation of HostEnsureCanCompileWasmBytes may complete normally or +abruptly. Any abrupt completions will be propagated to its callers. The default +implementation of HostEnsureCanCompileWasmBytes is to unconditionally return an +empty normal completion. +

Implementation-defined Limits

The WebAssembly core specification allows an implementation to define limits on the syntactic structure of the module. From 13fcaec9ae0b89a27e7db013f3e98c7e0e12c5ee Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Thu, 8 Mar 2018 15:40:14 -0800 Subject: [PATCH 46/59] Add HostEnsureCanCompileWasmBytes hook for CSP --- document/js-api/index.bs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 4451ddf6cc..7674e9a63a 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -505,6 +505,7 @@ The verification of WebAssembly type requirements is deferred to the
The instantiate(|bytes|, |importObject|) method, when invoked, performs the following steps: 1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|. + 1. Perform [$HostEnsureCanCompileWasmBytes()$] 1. [=Asynchronously compile a WebAssembly module=] from |stableBytes| and let |promiseOfModule| be the result. 1. [=Instantiate a promise of a module|Instantiate=] |promiseOfModule| with imports |importObject| and return the result.
@@ -593,7 +594,7 @@ interface Module { The Module(|bytes|) constructor, when invoked, performs the follwing steps: 1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|. - 1. Perform [$HostEnsureCanCompileWasmBytes()$] + 1. Perform [$HostEnsureCanCompileWasmBytes(bytes)|HostEnsureCanCompileWasmBytes(stableBytes)$] 1. [=Compile a WebAssembly module|Compile the WebAssembly module=] |stableBytes| and store the result as |module|. 1. If |module| is [=error=], throw a {{CompileError}} exception. 1. Set **this**.\[[Module]] to |module|. @@ -1209,9 +1210,9 @@ Note: ECMAScript doesn't specify any sort of behavior on out-of-memory condition

Implementation-defined Operations

-

HostEnsureCanCompileWasmBytes()

+

HostEnsureCanCompileWasmBytes(bytes)

-HostEnsureCanCompileWasmBytes is an implementation-defined abstract operation +HostEnsureCanCompileWasmBytes(bytes) is an implementation-defined abstract operation that allows host environments to block certain WebAssembly functions which compile bytes into WebAssembly code. From c3996e8c1459a0bd42ae1cf531778e4bfd5ee5be Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Mon, 10 May 2021 11:03:49 -0700 Subject: [PATCH 47/59] Revised and simplified note --- proposals/CSP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index efba3e8880..4708f6295c 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -15,7 +15,7 @@ By imposing this sandbox on the execution of a WebAssembly model, the browser (o This does not, however, provide any guarantees that WebAssembly modules compute correct results: it is still possible that an incorrectly programmed module may corrupt data, produce invalid results and be subject to attacks such as SQL injection and even buffer overrun affecting data structures within an application. Since the memory used by a WebAssembly module may be shared via ArrayBuffers these faults may be visible to and affect other WebAssembly and JavaScript modules that also share the same memory. Other memory faults - such as use-after-free and accessing uninitialized memory - are also similarly not protected against by the engine. We should also note that a malicious module may be completely safe in terms of the resources from the host that it uses and still cause significant harm to the user. A classic example of this would be a surruptiously loaded crypto-mining WebAssembly module. - +a In addition, the sandbox model does not manage _which_ WebAssembly modules are executed. Controlling which WebAssembly modules are executed is the primary focus of CSP. ### CSP Resource Control From 9247d8d495f6a18a3a38567a01362d489f3bb469 Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Tue, 11 May 2021 14:37:56 -0700 Subject: [PATCH 48/59] Changed wasm-eval to wasm-unsafe-eval --- proposals/CSP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/CSP.md b/proposals/CSP.md index 4708f6295c..efba3e8880 100644 --- a/proposals/CSP.md +++ b/proposals/CSP.md @@ -15,7 +15,7 @@ By imposing this sandbox on the execution of a WebAssembly model, the browser (o This does not, however, provide any guarantees that WebAssembly modules compute correct results: it is still possible that an incorrectly programmed module may corrupt data, produce invalid results and be subject to attacks such as SQL injection and even buffer overrun affecting data structures within an application. Since the memory used by a WebAssembly module may be shared via ArrayBuffers these faults may be visible to and affect other WebAssembly and JavaScript modules that also share the same memory. Other memory faults - such as use-after-free and accessing uninitialized memory - are also similarly not protected against by the engine. We should also note that a malicious module may be completely safe in terms of the resources from the host that it uses and still cause significant harm to the user. A classic example of this would be a surruptiously loaded crypto-mining WebAssembly module. -a + In addition, the sandbox model does not manage _which_ WebAssembly modules are executed. Controlling which WebAssembly modules are executed is the primary focus of CSP. ### CSP Resource Control From 31ede6be0ca2066cf6164159b6c15d80a96ab58a Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Mon, 30 Aug 2021 14:44:55 -0700 Subject: [PATCH 49/59] Removed funny dangling entry --- document/web-api/index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/web-api/index.bs b/document/web-api/index.bs index db6ecaa8c9..a49785d816 100644 --- a/document/web-api/index.bs +++ b/document/web-api/index.bs @@ -125,7 +125,7 @@ Note: This algorithm accepts a {{Response}} object, or a promise for one, and Note: extra parameters are not allowed, including the empty `` `application/wasm;` ``. - 1. If |response| is not [=CORS-same-origin=], [=reject=] |returnValue| with a {{TypeError}} and abort these substeps. + 4. If |response| is not [=CORS-same-origin=], [=reject=] |returnValue| with a {{TypeError}} and abort these substeps. 1. If |response|'s [=response/status=] is not an [=ok status=], [=reject=] |returnValue| with a {{TypeError}} and abort these substeps. 1. Perform [$HostEnsureCanCompileWasmBytes()$] 1. [=Consume body|consume=] |response|'s body as an {{ArrayBuffer}}, and let |bodyPromise| be the result. From c274959cf844cbcc201859b5c4703837d54f9ff5 Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Mon, 18 Apr 2022 13:31:27 -0700 Subject: [PATCH 50/59] Ensure compile as well as compile streaming guarded --- document/js-api/index.bs | 5 ++++- document/web-api/index.bs | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 7674e9a63a..4fb7a7d229 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -308,6 +308,9 @@ Note:
To compile a WebAssembly module from source bytes |bytes|, perform the following steps: + 1. Perform [$HostEnsureCanCompileWasmBytes()$]. + + Note: This operation terminates with a {{CompileError}} exception if the operation is not permitted. 1. Let |module| be [=module_decode=](|bytes|). If |module| is [=error=], return [=error=]. 1. If [=module_validate=](|module|) is [=error=], return [=error=]. 1. Return |module|. @@ -1258,7 +1261,7 @@ In practice, an implementation may run out of resources for valid modules below

Implementation-defined Operations

-

HostEnsureCanCompileWasmBytes(s)

+

HostEnsureCanCompileWasmBytes()

HostEnsureCanCompileWasmBytes() is an implementation-defined abstract operation that allows host environments to block certain WebAssembly functions which diff --git a/document/web-api/index.bs b/document/web-api/index.bs index a49785d816..bfc5247244 100644 --- a/document/web-api/index.bs +++ b/document/web-api/index.bs @@ -127,7 +127,10 @@ Note: This algorithm accepts a {{Response}} object, or a promise for one, and 4. If |response| is not [=CORS-same-origin=], [=reject=] |returnValue| with a {{TypeError}} and abort these substeps. 1. If |response|'s [=response/status=] is not an [=ok status=], [=reject=] |returnValue| with a {{TypeError}} and abort these substeps. - 1. Perform [$HostEnsureCanCompileWasmBytes()$] + 1. Perform [$HostEnsureCanCompileWasmBytes()$]. + + Note: This operation terminates with a {{CompileError}} exception if the operation is not permitted. + 1. [=Consume body|consume=] |response|'s body as an {{ArrayBuffer}}, and let |bodyPromise| be the result. Note: Although it is specified here that the response is consumed entirely before compilation proceeds, that is purely for ease of specification; implementations are likely to instead perform processing in a streaming fashion. The difference is unobservable, and thus the simpler model is specified. From 2746eae8eacf7e71b8b30158da589bc0a781ed01 Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Mon, 18 Apr 2022 14:32:44 -0700 Subject: [PATCH 51/59] Remove duplicate text --- document/js-api/index.bs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 4fb7a7d229..87f3224c03 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -1211,19 +1211,6 @@ Note: ECMAScript doesn't specify any sort of behavior on out-of-memory condition See [Issue 879](https://github.com/WebAssembly/spec/issues/879) for further discussion.
-

Implementation-defined Operations

- -

HostEnsureCanCompileWasmBytes(bytes)

- -HostEnsureCanCompileWasmBytes(bytes) is an implementation-defined abstract operation -that allows host environments to block certain WebAssembly functions which -compile bytes into WebAssembly code. - -An implementation of HostEnsureCanCompileWasmBytes may complete normally or -abruptly. Any abrupt completions will be propagated to its callers. The default -implementation of HostEnsureCanCompileWasmBytes is to unconditionally return an -empty normal completion. -

Implementation-defined Limits

The WebAssembly core specification allows an implementation to define limits on the syntactic structure of the module. From 011ae571f312847437aae3afd422688db7c04857 Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Wed, 16 Jul 2025 11:11:44 -0700 Subject: [PATCH 52/59] Take out use of HostEnsureCanCompileWasmBytes from web-api Redundant: already covered in js-api --- document/js-api/index.bs | 1 - 1 file changed, 1 deletion(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 6c7a47d910..dee4fb4ac6 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -594,7 +594,6 @@ interface Module { The Module(|bytes|) constructor, when invoked, performs the following steps: 1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|. - 1. Perform [$HostEnsureCanCompileWasmBytes(bytes)|HostEnsureCanCompileWasmBytes(stableBytes)$] 1. [=Compile a WebAssembly module|Compile the WebAssembly module=] |stableBytes| and store the result as |module|. 1. If |module| is [=error=], throw a {{CompileError}} exception. 1. Set **this**.\[[Module]] to |module|. From 04b038827784caaea07b730d452b652c0bc973fb Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Wed, 16 Jul 2025 11:49:31 -0700 Subject: [PATCH 53/59] Drop some spaces --- document/web-api/index.bs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/document/web-api/index.bs b/document/web-api/index.bs index 9cef601347..ed90402ebd 100644 --- a/document/web-api/index.bs +++ b/document/web-api/index.bs @@ -129,10 +129,8 @@ Note: This algorithm accepts a {{Response}} object, or a 1. If |response| is not [=CORS-same-origin=], [=reject=] |returnValue| with a {{TypeError}} and abort these substeps. 1. If |response|'s [=response/status=] is not an [=ok status=], [=reject=] |returnValue| with a {{TypeError}} and abort these substeps. - 1. Perform [$HostEnsureCanCompileWasmBytes()$]. - + 1. Perform [$HostEnsureCanCompileWasmBytes()$]. Note: This operation terminates with a {{CompileError}} exception if the operation is not permitted. - 1. [=Consume body|consume=] |response|'s body as an {{ArrayBuffer}}, and let |bodyPromise| be the result. Note: Although it is specified here that the response is consumed entirely before compilation proceeds, that is purely for ease of specification; implementations are likely to instead perform processing in a streaming fashion. The difference is unobservable, and thus the simpler model is specified. From 9f09100f6081170545f9ebc44d705ea2918e0e91 Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Wed, 16 Jul 2025 11:55:32 -0700 Subject: [PATCH 54/59] Drop more spaces --- document/js-api/index.bs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 99d807e13d..f16f2e60da 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -379,8 +379,7 @@ Note:
To compile a WebAssembly module from source bytes |bytes|, perform the following steps: - 1. Perform [$HostEnsureCanCompileWasmBytes()$]. - + 1. Perform [$HostEnsureCanCompileWasmBytes()$]. Note: This operation terminates with a {{CompileError}} exception if the operation is not permitted. 1. Let |module| be [=module_decode=](|bytes|). If |module| is [=error=], return [=error=]. 1. If [=module_validate=](|module|) is [=error=], return [=error=]. From 7c1478f7365993799e26098db15f1fe048396827 Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Wed, 16 Jul 2025 12:00:02 -0700 Subject: [PATCH 55/59] Add back section on implementation defined operations --- document/js-api/index.bs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index f16f2e60da..99ca3c6b5b 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -1785,6 +1785,18 @@ Note: ECMAScript doesn't specify any sort of behavior on out-of-memory condition See [Issue 879](https://github.com/WebAssembly/spec/issues/879) for further discussion.
+

Implementation-defined Operations

+ +

HostEnsureCanCompileWasmBytes(bytes)

+ +HostEnsureCanCompileWasmBytes(bytes) is an implementation-defined abstract operation +that allows host environments to block certain WebAssembly functions which +compile bytes into WebAssembly code. + +An implementation of HostEnsureCanCompileWasmBytes may complete normally or +abruptly. Any abrupt completions will be propagated to its callers. The default +implementation of HostEnsureCanCompileWasmBytes is to unconditionally return an +empty normal completion.

Implementation-defined Limits

From 2b81a760974ab0042389ff3aa0c3150a38fad6dc Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Wed, 16 Jul 2025 12:02:05 -0700 Subject: [PATCH 56/59] Remove bytes argument from HostEnsureCanCompileWasmBytes --- document/js-api/index.bs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 99ca3c6b5b..f98b3ccaeb 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -1787,9 +1787,9 @@ Note: ECMAScript doesn't specify any sort of behavior on out-of-memory condition

Implementation-defined Operations

-

HostEnsureCanCompileWasmBytes(bytes)

+

HostEnsureCanCompileWasmBytes()

-HostEnsureCanCompileWasmBytes(bytes) is an implementation-defined abstract operation +HostEnsureCanCompileWasmBytes() is an implementation-defined abstract operation that allows host environments to block certain WebAssembly functions which compile bytes into WebAssembly code. From 48feb4b71f09d43b5b3360cfb7af1e42fd0a1c0b Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Wed, 16 Jul 2025 13:40:13 -0700 Subject: [PATCH 57/59] Fixed markdown indentation error --- document/js-api/index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index f98b3ccaeb..7a20996237 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -380,7 +380,7 @@ Note:
To compile a WebAssembly module from source bytes |bytes|, perform the following steps: 1. Perform [$HostEnsureCanCompileWasmBytes()$]. - Note: This operation terminates with a {{CompileError}} exception if the operation is not permitted. + Note: This operation terminates with a {{CompileError}} exception if the operation is not permitted. 1. Let |module| be [=module_decode=](|bytes|). If |module| is [=error=], return [=error=]. 1. If [=module_validate=](|module|) is [=error=], return [=error=]. 1. Return |module|. From 893da3bce56fbdf971e699495bd210a60f07e1bb Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Wed, 16 Jul 2025 14:11:39 -0700 Subject: [PATCH 58/59] Remove reference to HostEnsureWasmCanCompile Not needed in web-api spec. --- document/web-api/index.bs | 2 -- 1 file changed, 2 deletions(-) diff --git a/document/web-api/index.bs b/document/web-api/index.bs index ed90402ebd..2163646fb9 100644 --- a/document/web-api/index.bs +++ b/document/web-api/index.bs @@ -129,8 +129,6 @@ Note: This algorithm accepts a {{Response}} object, or a 1. If |response| is not [=CORS-same-origin=], [=reject=] |returnValue| with a {{TypeError}} and abort these substeps. 1. If |response|'s [=response/status=] is not an [=ok status=], [=reject=] |returnValue| with a {{TypeError}} and abort these substeps. - 1. Perform [$HostEnsureCanCompileWasmBytes()$]. - Note: This operation terminates with a {{CompileError}} exception if the operation is not permitted. 1. [=Consume body|consume=] |response|'s body as an {{ArrayBuffer}}, and let |bodyPromise| be the result. Note: Although it is specified here that the response is consumed entirely before compilation proceeds, that is purely for ease of specification; implementations are likely to instead perform processing in a streaming fashion. The difference is unobservable, and thus the simpler model is specified. From 8227401d52c4bdc16efcf0ab7e8e719571d2e23a Mon Sep 17 00:00:00 2001 From: Francis McCabe Date: Wed, 24 Jun 2026 11:03:11 -0700 Subject: [PATCH 59/59] Update README to remove CSP proposal details Removed the Content Security Policy proposal section from the README. --- README.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/README.md b/README.md index cea0fb0a4a..4dfd708d83 100644 --- a/README.md +++ b/README.md @@ -5,16 +5,6 @@ [![CI for specs](https://github.com/WebAssembly/spec/actions/workflows/ci-spec.yml/badge.svg)](https://github.com/WebAssembly/spec/actions/workflows/ci-spec.yml) [![CI for interpreter & tests](https://github.com/WebAssembly/spec/actions/workflows/ci-interpreter.yml/badge.svg)](https://github.com/WebAssembly/spec/actions/workflows/ci-interpreter.yml) -# Content Security Policy Proposal for WebAssembly - -This repository is a clone of github.com/WebAssembly/spec/. It is meant for -discussion, prototype specification and implementation of a proposal -to add better Content Security Policy (CSP) support to WebAssembly. - -See the [overview](proposals/CSP.md) for a summary of the proposal. - -Original README from upstream repository follows... - # spec