Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fine-grained Wasm execution policies #37

Open
guybedford opened this issue Oct 15, 2021 · 17 comments
Open

Fine-grained Wasm execution policies #37

guybedford opened this issue Oct 15, 2021 · 17 comments

Comments

@guybedford
Copy link

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 WebAssembly/esm-integration#56.

@fgmccabe
Copy link
Collaborator

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.

@didyk
Copy link

didyk commented Dec 6, 2021

@fgmccabe do you have any news about it? Looks like without it wasm can't run inside extensions with manifest v3

@fgmccabe
Copy link
Collaborator

fgmccabe commented Dec 6, 2021 via email

@Rdlenke
Copy link

Rdlenke commented Dec 9, 2021

@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:

Untitled

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.

@fgmccabe
Copy link
Collaborator

fgmccabe commented Dec 9, 2021

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'?

@Rdlenke
Copy link

Rdlenke commented Dec 9, 2021

Sure. Using

    "content_security_policy": {
        "extension_pages": "script-src 'self' 'unsafe-eval'; object-src 'self';"
    }

I still receive a similar error.

Untitled

@didyk
Copy link

didyk commented Dec 9, 2021

@DemiMarie
Copy link

@fgmccabe this is blocking Element from adopting a strong Content-Security-Policy

@guest271314
Copy link

You can remove the Content-Security-Policy header entirely using the extension.

@jacquelynoelle
Copy link

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.

@guest271314
Copy link

@jacquelynoelle I don't think you can guarantee that the client will not remove Content-Security-Policy headers altogether.

@guest271314
Copy link

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., backkem/local-devices-api#6, httpslocal/proposals#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 ServiceWorkers, 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.

@dotproto
Copy link

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 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.

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 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.

@fgmccabe
Copy link
Collaborator

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'.

@Rob--W
Copy link

Rob--W commented Jul 18, 2022

'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.

@OluAgunloye
Copy link

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 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.

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 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.

It makes the most sense of anything I've seen considered on the topic thus far.

@robyoder
Copy link

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='.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests