WebAssembly / content-security-policy

Other
38 stars 15 forks source link

Fine-grained Wasm execution policies #37

Open guybedford opened 2 years ago

guybedford commented 2 years ago

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.

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

didyk commented 2 years ago

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

fgmccabe commented 2 years ago

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

Rdlenke commented 2 years ago

@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 commented 2 years ago

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 commented 2 years ago

Sure. Using

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

I still receive a similar error.

Untitled

didyk commented 2 years ago

@fgmccabe You can see more details here: https://bugs.chromium.org/p/chromium/issues/detail?id=1173354&q=manifest%20v3&can=2

DemiMarie commented 2 years ago

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

guest271314 commented 2 years ago

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

jacquelynoelle commented 2 years ago

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 commented 2 years ago

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

guest271314 commented 2 years ago

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 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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

'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 commented 2 years ago

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 commented 1 year 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 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='.