Daninet / hash-wasm

Lightning fast hash functions using hand-tuned WebAssembly binaries
https://npmjs.com/package/hash-wasm
Other
882 stars 49 forks source link

WebAssembly conflict with restrictive CSP in Chrome #3

Open jens-duttke opened 4 years ago

jens-duttke commented 4 years ago

First, thanks for this great package! I'm using it in my web-application, where it works wonderful, even for very large files (> 10 GB).

Unfortunately, if a page has a restrictive Content-Security-Policy which does not allow 'unsafe-eval' for script-src, the WebAssembly.compile will fail with:

CompileError: WebAssembly.compile(): Wasm code generation disallowed by embedder

For more information see: https://github.com/WebAssembly/content-security-policy/issues/7 https://github.com/WebAssembly/content-security-policy/blob/master/proposals/CSP.md

I found a simply workaround which grabs the WebAssembly object from a page with 'unsafe-eval' set, and overwrites the object from the "main window". This is possible using this JavaScript:

// @ts-expect-error
window.WebAssembly = await (async () => new Promise((resolve) => {
    const iframe = document.createElement('iframe');

    // This page is using `Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-eval'`
    iframe.src = '/wasm/';

    iframe.addEventListener('load', () => {
        // @ts-expect-error
        const wasm = iframe.contentWindow?.WebAssembly ?? WebAssembly;

        document.body.removeChild(iframe);

        resolve(wasm);
    });

    document.body.appendChild(iframe);
}))();

So hash-wasm is using the WebAssembly object from the iframe with 'unsafe-eval' without to even know about this "hack".

Since I don't like overwriting global objects, I think it would be a nice feature to be able to provide the WebAssembly object, which it should use, directly to hash-wasm.

Daninet commented 4 years ago

You found a nice trick for escaping from the CSP rules. :) Could you tell me more about your use case? Why do they have this CSP in place?

I want to keep the API as simple as possible and I'm not convinced that it would be a feature, which is useful for most users. For those who have this CSP issue, I think it's acceptable to overwrite the global WebAssembly object, even if it's not nice.

Also, I'm concerned that this way of circumventing CSP will be closed in the future.

jens-duttke commented 4 years ago

Could you tell me more about your use case? Why do they have this CSP in place?

Some Browser extensions and internet providers injects code into websites, which sometimes massively manipulate the DOM and JavaScript objects. Beside that, it could be that data is also derived in this way.

I'm writing a web application (https://hexed.it) which can be used to analyse and edit any file locally. These files could contain sensitive data. I don't send any of these data to the server and I want to protect my users as much as possible from ISPs or Browser extensions doing that.

A very large part of these manipulations can be prevented by using a restrictive CSP.

Also, I'm concerned that this way of circumventing CSP will be closed in the future.

I'm in the hope that 'wasm-eval' will be available for websites in Chrome, before this "circumventing" get fixed.

Daninet commented 4 years ago

Your hex editor is very cool. :)

I heard about this practice of ISPs with HTTP websites, but I thought it isn't working anymore with HTTPS websites.

As far as I know, you couldn't stop browser extensions from reading website contents. Even if you block outgoing requests on your site, the extensions can collect the data into their localStorage and send it to a remote server next time, when another webpage is loaded without CSP. Extensions can even disable the CSP completely: https://chrome.google.com/webstore/detail/disable-content-security/ieelmcmcagommplceebfedjlakkhpden?hl=en

Daninet commented 4 years ago

To increase security, I think the best way is to overwrite each API call you don't use: fetch(), XMLHttpRequest(), Worker(), eval(), DOM API etc. But I think extensions can still access your content if they want.

jens-duttke commented 4 years ago

I heard about this practice of ISPs with HTTP websites, but I thought it isn't working anymore with HTTPS websites.

Especially for ISPs, I had this problem indeed only at a time where my page used HTTP. But the ISP and browser extensions are not the only ones, between the server and the user. Some examples can be found here: https://blog.cloudflare.com/monsters-in-the-middleboxes/

To increase security, I think the best way is to overwrite each API call you don't use

That doesn't work, because the same trick I've used for the WebAssembly object, works for almost everything else as well.

The CSP is the best way to prevent that connections to other servers can be established, and the restrictive script-src directive, decreased the number of JavaScript errors in my app massively.

Extensions can even disable the CSP completely

When an extension does that secretly, there should be a good chance, that such an extension get removed/disabled by the browser vendor.