w3c / webappsec-csp

WebAppSec Content Security Policy
https://w3c.github.io/webappsec-csp/
Other
210 stars 78 forks source link

Regarding hashes for JS URL #553

Open seongil-wi opened 2 years ago

seongil-wi commented 2 years ago

Hello team,

I leave an issue because there is an ambiguity in the hashing for JS URLs (javascript:[JS]).

The CSP spec mentions that hash-source can be applied to javascript: navigation (https://www.w3.org/TR/CSP3/#match-element-to-source-list)

If the "['unsafe-hashes'](https://www.w3.org/TR/CSP3/#grammardef-unsafe-hashes)" source expression is present, they will also apply to event handlers, style attributes and javascript: navigations.

However it does not specify what exactly to hash (i.e., including javascript: or not).

In the wild,

Firefox only uses everything after "javascript:" (i.e., sha256("alert(1);")) to compute the hash value, hence, it executes the javascript url whe encountering the CSP: script-src 'sha256-5jFwrAK0UV47oFbVg/iCCBbxD8X1w+QvoOUepu4C2YA=' 'unsafe-hashes'.

In contrast to that, Chromium-based browsers and Safari use the entire attribute value (i.e., sha256("javascript:alert(1);")).

Thus when providing the hash value 'sha256-6rHS0m9l4sDJsB2k/Z3d/OJlJSv1H6Y6jKYIcK6zaks=' in the CSP, the javascript url would be executed in Chromium-based browsers and Safari.

There is no clear description in spec on whether the Chromium/Safari or Firefox behavior is correct. So which browser's behavior is correct? How about making the spec a bit more clear about this?

annevk commented 2 years ago

cc @mozfreddyb

antosart commented 2 years ago

Note: This is confirmed by web platform tests, which include javascript: in the hash computation and indeed are passing on Chrome/Safari but not on Firefox: https://wpt.fyi/results/content-security-policy/unsafe-hashes?label=experimental&label=master&aligned

mozfreddyb commented 2 years ago

First of all, I don't think Firefox supports unsafe-hashes. Secondly, I find it a bit counter-intuitive that we require a hash of the attribute and not the hash of the JavaScript code.

annevk commented 2 years ago

Isn't that what's done for the script element contents as well? How would you canonicalize whitespace and such otherwise?

antosart commented 2 years ago

I think according to the spec, the hash should be computed using the whole url, including the javascript: prefix, since the whole URL is passed in the algorithm https://www.w3.org/TR/CSP3/#should-block-navigation-request at 3.1.1.2.

mozfreddyb commented 2 years ago

@seongil-wi Given Firefox's non-support for unsafe-hashes, can you share a test case for me to better understand (and file a bug in our tracker)?

seongil-wi commented 2 years ago

@mozfreddyb As you said, Firefox does not support unsafe-hashes in script-src directive, but instead it behaves as if the unsafe-hashes expression is auto-enabled (https://bugzilla.mozilla.org/show_bug.cgi?id=1683506). That is, even if an unsafe-hashes expression is not specified in script-src, it will be executed if the hash specified in script-src is matched for event handlers or JavaScript URL navigation.

Here is a test case that only runs on firefox, not on Chrome and Safari by CSP.

<html>
  <head>
    <meta http-equiv="Content-Security-Policy" content="script-src 'sha256-5jFwrAK0UV47oFbVg/iCCBbxD8X1w+QvoOUepu4C2YA='">
  </head>
<html>
  <iframe src="javascript:alert(1);">
  </iframe>
</html>

Firefox only uses everything after "javascript:" (i.e., sha256("alert(1);")) to compute the hash value, hence, it executes the javascript URL when encountering the CSP: script-src 'sha256-5jFwrAK0UV47oFbVg/iCCBbxD8X1w+QvoOUepu4C2YA='.

I'll share this on firefox tracker as well.