Open guybedford opened 2 years ago
This is aligned with my thinking also. Likely to take longer than wasm-unsafe-eval but a new nonce-based CSP policy source (tentatively called wasm-src) is on our minds.
@fgmccabe do you have any news about it? Looks like without it wasm can't run inside extensions with manifest v3
Can you explain a little more? Francis
On Mon, Dec 6, 2021 at 3:30 AM Dmitriy @.***> wrote:
@fgmccabe https://github.com/fgmccabe do you have any news about it? Looks like without it wasm can't run inside extensions with manifest v3
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/WebAssembly/content-security-policy/issues/37#issuecomment-986689842, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAQAXUGNVBDKNGF47SI3HK3UPSNETANCNFSM5GCOD3YA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.
-- Francis McCabe SWE
@fgmccabe If an extension specifies wasm-unsafe-eval
or wasm-eval
in the new CSP object for manifest v3, chrome will show an error.
For example, using:
"content_security_policy": {
"extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';"
}
Chrome shows:
I assume that this happens because manifest v3 tries to restrict remote-code execution, and that's why it works that way. However...
@didyk Have you tried specifying your policy without wasm-unsafe-eval
, or even without specifying the CSP object entirely? Like:
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self';"
}
I did some tests and noticed that I can simply not specify the CSP and Chrome will accept an extension with WASM code. However, I'm not sure how this factors in the publishing process.
I can try looking into this. It 'smells' of an integration issue. Can you try an experiment for me? Use 'unsafe-eval' instead of 'wasm-unsafe-eval'?
Sure. Using
"content_security_policy": {
"extension_pages": "script-src 'self' 'unsafe-eval'; object-src 'self';"
}
I still receive a similar error.
@fgmccabe You can see more details here: https://bugs.chromium.org/p/chromium/issues/detail?id=1173354&q=manifest%20v3&can=2
@fgmccabe this is blocking Element from adopting a strong Content-Security-Policy
You can remove the Content-Security-Policy
header entirely using the extension.
Also just wanted to express interest in this on behalf of Tableau/Salesforce. We use WebAssembly and have been following the wasm-unsafe-eval
progress closely. (Thank you!) Our security teams and some customers are starting to get more serious about Content Security Policy, and without the recent adoption of wasm-unsafe-eval
by the major browsers we support, I think we'd be having to have some serious conversations about whether we could continue to use WebAssembly. This new CSP directive should buy us time, but long-term, we're definitely going to be looking for something like what @guybedford and @fgmccabe suggested.
@jacquelynoelle I don't think you can guarantee that the client will not remove Content-Security-Policy
headers altogether.
For clarity I'll post an example here of removing all CSP headers using an extension, to demonstrate what I mentioned in earlier posts.
The purpose of doing that is for the capability to fetch()
localhost or files in an extension from any origin, which is a use case for several proposals, e.g., https://github.com/backkem/local-devices-api/issues/6, https://github.com/httpslocal/proposals/issues/2.
Thus, while you can specify Content-Security-Policy
goals, and even have vendors implement them, you cannot guarantee that I, or other users in the field will not remove them, making such headers useless if you are really expecting them to restrict certain code from running.
https://github.com/guest271314/remove-csp-header
manifest.json
{
"name": "Remove Content-Security-Policy header",
"manifest_version": 3,
"version": "1.0",
"declarative_net_request" : {
"rule_resources" : [{
"id": "ruleset_1",
"enabled": true,
"path": "rules_1.json"
}]
},
"permissions": [
"declarativeNetRequest"
],
"host_permissions": [
"<all_urls>"
],
"author": "guest271314"
}
rules_1.json
[
{
"id": 1,
"priority": 1,
"action": {
"type": "modifyHeaders",
"responseHeaders": [
{
"header": "content-security-policy",
"operation": "remove"
},
{
"header": "content-security-policy-report-only",
"operation": "remove"
}
]
},
"condition": {
"regexFilter": "^*://*/*",
"resourceTypes": [
"main_frame"
]
}
}
]
Then at the local server I can do something like the following, note the Access-Control-Allow-Private-Network: true
header, see https://wicg.github.io/private-network-access/.
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST");
header("Access-Control-Allow-Headers: Access-Control-Request-Private-Network");
header("Access-Control-Allow-Private-Network: true");
header("Content-Type: application/octet-stream");
header('Vary: Origin');
header("X-Powered-By:");
echo "localhost";
Tested on GitHub, Twitter (which uses ServiceWorker
s, too), and several other Web sites that are served with CSP headers.
So, I would not rely on Content-Security-Policy
headers for "Fine-grained Wasm execution policies", particularly at scale. You might be thinking your execution context is "secure" - but you can't control what the client does on their own machine.
Browser members of the WebExtensions Community Group are considering how to enable extensions to use Wasm that is bundled with an extension while preventing execution of arbitrary Wasm code. To that end, I originally came to this issue to ask whether it was possible for UAs to distinguish how Wasm resources are loaded, but ended up digging into the Wasm & CSP specs.
The working draft of CSP Level 3 has an Integration with WebAssembly section. This section indicates that the Wasm spec includes a HostEnsureCanCompileWasmBytes()
abstract operation. At the moment this appears to be slightly inaccurate; this abstract operation is defined in the js-api spec from this project. Currently, this project's definition of HostEnsureCanCompileWasmBytes()
defers to the CSP spec's definition of EnsureCSPDoesNotBlockWasmByteCompilation.
This repo also integrates HostEnsureCanCompileWasmBytes()
into several other operations:
The current set of specs appear to cover everything necessary for CSP to control Wasm compilation and using the script-src
directive and wasm-unsafe-eval
value.
In order for browsers to limit an extension's ability to run Wasm to files loaded from the extension's bundle, the WebExtension platform will need to be able to declare a base CSP policy that contains a Wasm equivalent of script-src 'self';
. The two main strategies I see to accomplish this are to either extend script-src
to also apply to Wasm or introduce a new wasm-src
directive to specifically control Wasm compilation and instantiation. Personally, I'm in favor of introducing a new Wasm-specific directive.
There has been a separate, yet related, effort to incorporate wasm-unsafe-eval into Chrome's V3 Extension manifest. The default CSP there is script-src: 'self', as you suggest. It is permitted to use script-src: ... 'wasm-unsafe-eval'.
'wasm-unsafe-eval'
is currently a way to either enable or disable wasm altogether. WASM is currently initialized from bytes (typed array or Response). Because of this, if a wasm-src
directive were to be introduced, then it would only feasibly be applicable to the WebAssembly.compileStreaming
and WebAssembly.instantiateStreaming
methods, provided that it is feasible to reliably attribute the Response to the real origin of the wasm data.
For extensions, it would also be very desirable to have strict MIME type (and/or file extension) requirements, so that extensions cannot hide wasm code in a png file for example.
There has been a separate, yet related, effort to incorporate wasm-unsafe-eval into Chrome's V3 Extension manifest. The default CSP there is script-src: 'self', as you suggest. It is permitted to use script-src: ... 'wasm-unsafe-eval'.
wasm-unsafe-eval
is allowed in extensions to use wasm in the absence of anything better. The Chromium engineer that introduced support for 'wasm-unsafe-eval'
(i.e. @fgmccabe) has shared some thoughts on wasm in Chrome extensions at https://bugs.chromium.org/p/chromium/issues/detail?id=1173354#c55, where he also stated that a wasm-src
would be ideal and that wasm-unsafe-eval
is a quasi-temporary fix.
Browser members of the WebExtensions Community Group are considering how to enable extensions to use Wasm that is bundled with an extension while preventing execution of arbitrary Wasm code. To that end, I originally came to this issue to ask whether it was possible for UAs to distinguish how Wasm resources are loaded, but ended up digging into the Wasm & CSP specs.
Current state of Wasm & CSP
The working draft of CSP Level 3 has an Integration with WebAssembly section. This section indicates that the Wasm spec includes a
HostEnsureCanCompileWasmBytes()
abstract operation. At the moment this appears to be slightly inaccurate; this abstract operation is defined in the js-api spec from this project. Currently, this project's definition ofHostEnsureCanCompileWasmBytes()
defers to the CSP spec's definition of EnsureCSPDoesNotBlockWasmByteCompilation.This repo also integrates
HostEnsureCanCompileWasmBytes()
into several other operations:
- js-api: compile a WebAssembly module
- js-api: instantiate(bytes, importObject)
- js-api: Module(bytes), which in turn references compile a WebAssembly module
- web-api: compile a potential WebAssembly response
The current set of specs appear to cover everything necessary for CSP to control Wasm compilation and using the
script-src
directive andwasm-unsafe-eval
value.Origin-based Wasm restrictions
In order for browsers to limit an extension's ability to run Wasm to files loaded from the extension's bundle, the WebExtension platform will need to be able to declare a base CSP policy that contains a Wasm equivalent of
script-src 'self';
. The two main strategies I see to accomplish this are to either extendscript-src
to also apply to Wasm or introduce a newwasm-src
directive to specifically control Wasm compilation and instantiation. Personally, I'm in favor of introducing a new Wasm-specific directive.
It makes the most sense of anything I've seen considered on the topic thus far.
This is aligned with my thinking also. Likely to take longer than wasm-unsafe-eval but a new nonce-based CSP policy source (tentatively called wasm-src) is on our minds.
@fgmccabe is there a reason not to support origins and SRI hashes like script-src does? I was encouraged a few years ago at this part of the proposal specifying how the trusted origin of Response
objects could be used to gate allowed WASM modules, in addition to SRI hashes.
I'd love to see these ideas carried forward to a wasm-src
proposal so that we could write things like wasm-src https://example.com
or wasm-src 'sha256-R4GRiHQRLfTbaX0vl8FW9oTeyB6jQapLpSKa0ahnDTQ='
.
Currently with
wasm-unsafe-eval
there is no distinction between Wasm being executed from a trusted source versus Wasm being executed from an untrusted source.One of the primary features of CSP is being able to define trusted executions either associated with non-CDN domains that have restricted code available or via a nonce which carries the execution stamp of approval as it were.
Perhaps a
wasm-src
CSP option or similar could be used to distinguish Wasm execution sources on the web? Would something like that be a possibility? Even just avoiding the "unsafe" prefix helps in ensuring the right security messaging here.I'm specifically thinking about this in regards to the ESM integration, per https://github.com/WebAssembly/esm-integration/issues/56.