diff options
Diffstat (limited to 'testing/web-platform/tests/fetch/corb')
66 files changed, 907 insertions, 0 deletions
diff --git a/testing/web-platform/tests/fetch/corb/README.md b/testing/web-platform/tests/fetch/corb/README.md new file mode 100644 index 0000000000..f29562b060 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/README.md @@ -0,0 +1,67 @@ +# Tests related to Cross-Origin Resource Blocking (CORB). + +### Summary + +This directory contains tests related to the +[Cross-Origin Resource Blocking (CORB)](https://chromium.googlesource.com/chromium/src/+/main/services/network/cross_origin_read_blocking_explainer.md) +algorithm. + +The tests in this directory interact with various, random features, +but the tests have been grouped together into the `fetch/corb` directory, +because all of these tests verify behavior that is important to the CORB +algorithm. + + +### CORB is not universally implemented yet + +CORB has been included +in the [Fetch spec](https://fetch.spec.whatwg.org/#corb) +since [May 2018](https://github.com/whatwg/fetch/pull/686). + +Some tests in this directory (e.g. +`css-with-json-parser-breaker`) cover behavior spec-ed outside of CORB (making +sure that CORB doesn't change the existing web behavior) and therefore are +valuable independently from CORB's standardization efforts and should already +be passing across all browsers. + +Tests that cover behavior that is changed by CORB are currently marked as +[tentative](https://web-platform-tests.org/writing-tests/file-names.html) +(using `.tentative` substring in their filename). +Such tests may fail unless CORB is enabled. In practice this means that: +* Such tests will pass in Chromium + (where CORB is enabled by default [since M68](https://crrev.com/553830)). +* Such tests may fail in other browsers. + + +### Limitations of WPT test coverage + +CORB is a defense-in-depth and in general should not cause changes in behavior +that can be observed by web features or by end users. This makes CORB difficult +or even impossible to test via WPT. + +WPT tests can cover the following: + +* Helping verify CORB has no observable impact in specific scenarios. + Examples: + * image rendering of (an empty response of) a html document blocked by CORB + should be indistinguishable from rendering such html document without CORB - + `img-html-correctly-labeled.sub.html` + * CORB shouldn't block responses that don't sniff as a CORB-protected document + type - `img-png-mislabeled-as-html.sub.html` +* Helping document cases where CORB causes observable changes in behavior. + Examples: + * blocking of nosniff images labeled as non-image, CORB-protected + Content-Type - `img-png-mislabeled-as-html-nosniff.tentative.sub.html` + * blocking of CORB-protected documents can prevent triggering + syntax errors in scripts - + `script-html-via-cross-origin-blob-url.tentative.sub.html` +* Helping verify which MIME types are protected by CORB. + +Examples of aspects that WPT tests cannot cover (these aspects have to be +covered in other, browser-specific tests): +* Verifying that CORB doesn't affect things that are only indirectly + observable by the web (like + [prefetch](https://html.spec.whatwg.org/#link-type-prefetch). +* Verifying that CORB strips headers of blocked responses. +* Verifying that CORB blocks responses before they reach the process hosting + a cross-origin execution context. diff --git a/testing/web-platform/tests/fetch/corb/img-html-correctly-labeled.sub-ref.html b/testing/web-platform/tests/fetch/corb/img-html-correctly-labeled.sub-ref.html new file mode 100644 index 0000000000..0e75596952 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/img-html-correctly-labeled.sub-ref.html @@ -0,0 +1,4 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<!-- Same-origin, so the HTTP response is not CORB-eligible --> +<img src="resources/html-correctly-labeled.html"> diff --git a/testing/web-platform/tests/fetch/corb/img-html-correctly-labeled.sub.html b/testing/web-platform/tests/fetch/corb/img-html-correctly-labeled.sub.html new file mode 100644 index 0000000000..844cd0c927 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/img-html-correctly-labeled.sub.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<!-- Test verifies that html fed to an <img> tag doesn't have any observable + difference with and without CORB (in both cases the resource body cannot be + rendered as an image - html cannot be rendered as an image and the empty body + from a CORB-blocked response also cannot be rendered as an image). +--> +<meta charset="utf-8"> +<!-- Reference page uses same-origin resources, which are not CORB-eligible. --> +<link rel="match" href="img-html-correctly-labeled.sub-ref.html"> +<!-- www1 is cross-origin, so the HTTP response is CORB-eligible --> +<img src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/html-correctly-labeled.html"> diff --git a/testing/web-platform/tests/fetch/corb/img-mime-types-coverage.tentative.sub.html b/testing/web-platform/tests/fetch/corb/img-mime-types-coverage.tentative.sub.html new file mode 100644 index 0000000000..e2386de2f2 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/img-mime-types-coverage.tentative.sub.html @@ -0,0 +1,85 @@ +<!-- Test verifies that cross-origin, nosniff images are 1) blocked when their + MIME type is covered by CORB and 2) allowed otherwise. + + This test is very similar to fetch/nosniff/images.html, except that + 1) it deals with cross-origin images (CORB ignores same-origin fetches), + 2) it focuses on MIME types relevant to CORB. + There are opportunities to unify the test here with nosniff tests *if* + we can also start blocking same-origin (or cors-allowed) images. We + should try to gather data to quantify the impact of such change. +--> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> + var passes = [ + // Empty or non-sensical MIME types + null, "", "x", "x/x", + + // MIME-types not protected by CORB + "image/gif", "image/png", "image/png;blah", "image/svg+xml", + "application/javascript", "application/jsonp", + "application/dash+xml", // video format + "image/gif;HI=THERE", + + // Non-image MIME-types that in practice get used for images on the web. + // + // https://bugzilla.mozilla.org/show_bug.cgi?id=1302539 + "application/octet-stream", + // https://crbug.com/990853 + "application/x-www-form-urlencoded", + + // MIME types that may seem to be JSON or XML, but really aren't - i.e. + // these MIME types are not covered by: + // - https://mimesniff.spec.whatwg.org/#json-mime-type + // - https://mimesniff.spec.whatwg.org/#xml-mime-type + // - https://tools.ietf.org/html/rfc6839 + // - https://tools.ietf.org/html/rfc7303 + "text/x-json", "text/json+blah", "application/json+blah", + "text/xml+blah", "application/xml+blah", + "application/blahjson", "text/blahxml"] + + var fails = [ + // CORB-protected MIME-types - i.e. ones covered by: + // - https://mimesniff.spec.whatwg.org/#html-mime-type + // - https://mimesniff.spec.whatwg.org/#json-mime-type + // - https://mimesniff.spec.whatwg.org/#xml-mime-type + "text/html", + "text/json", "application/json", "text/xml", "application/xml", + "application/blah+json", "text/blah+json", + "application/blah+xml", "text/blah+xml", + "TEXT/HTML", "TEXT/JSON", "TEXT/BLAH+JSON", "APPLICATION/BLAH+XML", + "text/json;does=it;matter", "text/HTML;NO=it;does=NOT"] + + const get_url = (mime) => { + // www1 is cross-origin, so the HTTP response is CORB-eligible --> + url = "http://{{domains[www1]}}:{{ports[http][0]}}" + url = url + "/fetch/nosniff/resources/image.py" + if (mime != null) { + url += "?type=" + encodeURIComponent(mime) + } + return url + } + + passes.forEach(function(mime) { + async_test(function(t) { + var img = document.createElement("img") + img.onerror = t.unreached_func("Unexpected error event") + img.onload = t.step_func_done(function(){ + assert_equals(img.width, 96) + }) + img.src = get_url(mime) + document.body.appendChild(img) + }, "CORB should allow the response if Content-Type is: '" + mime + "'. ") + }) + + fails.forEach(function(mime) { + async_test(function(t) { + var img = document.createElement("img") + img.onerror = t.step_func_done() + img.onload = t.unreached_func("Unexpected load event") + img.src = get_url(mime) + document.body.appendChild(img) + }, "CORB should block the response if Content-Type is: '" + mime + "'. ") + }) +</script> diff --git a/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub-ref.html b/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub-ref.html new file mode 100644 index 0000000000..a771ed6a65 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub-ref.html @@ -0,0 +1,4 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<!-- Same-origin, so the HTTP response is not CORB-eligible --> +<img src="resources/empty-labeled-as-png.png"> diff --git a/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub.html b/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub.html new file mode 100644 index 0000000000..82adc47b0c --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<!-- Test verifies that CORB blocks an image mislabeled as text/html if + sniffing is disabled via `X-Content-Type-Options: nosniff` response header. + This has an observable effect (the image stops rendering), compared to the + behavior with no CORB. +--> +<meta charset="utf-8"> +<!-- Reference page uses same-origin resources, which are not CORB-eligible. --> +<link rel="match" href="img-png-mislabeled-as-html-nosniff.tentative.sub-ref.html"> +<!-- www1 is cross-origin, so the HTTP response is CORB-eligible --> +<img src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/png-mislabeled-as-html-nosniff.png"> diff --git a/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html.sub-ref.html b/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html.sub-ref.html new file mode 100644 index 0000000000..ebb337dba8 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html.sub-ref.html @@ -0,0 +1,4 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<!-- Same-origin, so the HTTP response is not CORB-eligible --> +<img src="resources/png-correctly-labeled.png"> diff --git a/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html.sub.html b/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html.sub.html new file mode 100644 index 0000000000..1ae4cfcaa7 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html.sub.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<!-- Test verifies that CORB won't block an image after sniffing determines + that the text/html Content-Type response header doesn't match the response + body. +--> +<meta charset="utf-8"> +<!-- Reference page uses same-origin resources, which are not CORB-eligible. --> +<link rel="match" href="img-png-mislabeled-as-html.sub-ref.html"> +<!-- www1 is cross-origin, so the HTTP response is CORB-eligible --> +<img src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/png-mislabeled-as-html.png"> diff --git a/testing/web-platform/tests/fetch/corb/img-svg-doctype-html-mimetype-empty.sub.html b/testing/web-platform/tests/fetch/corb/img-svg-doctype-html-mimetype-empty.sub.html new file mode 100644 index 0000000000..3219feda17 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/img-svg-doctype-html-mimetype-empty.sub.html @@ -0,0 +1,7 @@ +<!DOCTYPE html> +<!-- Verifies CORB/ORB SVG image blocking. + This image has no MIME type and an html DOCTYPE declaration and is + expected to be blocked--> +<meta charset="utf-8"> +<link rel="match" href="img-svg-invalid.sub-ref.html"> +<img src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/svg-doctype-html-mimetype-empty.svg"> diff --git a/testing/web-platform/tests/fetch/corb/img-svg-doctype-html-mimetype-svg.sub.html b/testing/web-platform/tests/fetch/corb/img-svg-doctype-html-mimetype-svg.sub.html new file mode 100644 index 0000000000..efcfaa2737 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/img-svg-doctype-html-mimetype-svg.sub.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<!-- Verifies CORB/ORB SVG image blocking. + This image has an SVG MIME type and an html DOCTYPE declaration and is + expected to load. + + This testcase is distilled from a bugreport and real web page. See: + https://crbug.com/1359788 +--> +<meta charset="utf-8"> +<link rel="match" href="img-svg.sub-ref.html"> +<img src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/svg-doctype-html-mimetype-svg.svg"> diff --git a/testing/web-platform/tests/fetch/corb/img-svg-invalid.sub-ref.html b/testing/web-platform/tests/fetch/corb/img-svg-invalid.sub-ref.html new file mode 100644 index 0000000000..484cd0a4fd --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/img-svg-invalid.sub-ref.html @@ -0,0 +1,5 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<!-- Same-origin, but invalid URL. + Serves as reference for tests that expect the image to be blocked. --> +<img src="resources/invalid.svg"> diff --git a/testing/web-platform/tests/fetch/corb/img-svg-labeled-as-dash.sub.html b/testing/web-platform/tests/fetch/corb/img-svg-labeled-as-dash.sub.html new file mode 100644 index 0000000000..0578b835fe --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/img-svg-labeled-as-dash.sub.html @@ -0,0 +1,6 @@ +<!DOCTYPE html> +<!-- Verifies CORB/ORB SVG image blocking. + This image is served with a DASH MIME type, and is expected to be blocked. --> +<meta charset="utf-8"> +<link rel="match" href="img-svg-invalid.sub-ref.html"> +<img src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/svg-labeled-as-dash.svg"> diff --git a/testing/web-platform/tests/fetch/corb/img-svg-labeled-as-svg-xml.sub.html b/testing/web-platform/tests/fetch/corb/img-svg-labeled-as-svg-xml.sub.html new file mode 100644 index 0000000000..30a2eb3246 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/img-svg-labeled-as-svg-xml.sub.html @@ -0,0 +1,6 @@ +<!DOCTYPE html> +<!-- Verifies CORB/ORB SVG image blocking. + This image is served with a proper SVG MIME type and is expected to load. --> +<meta charset="utf-8"> +<link rel="match" href="img-svg.sub-ref.html"> +<img src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/svg-labeled-as-svg-xml.svg"> diff --git a/testing/web-platform/tests/fetch/corb/img-svg-xml-decl.sub.html b/testing/web-platform/tests/fetch/corb/img-svg-xml-decl.sub.html new file mode 100644 index 0000000000..0d3aeafb25 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/img-svg-xml-decl.sub.html @@ -0,0 +1,6 @@ +<!DOCTYPE html> +<!-- Verifies CORB/ORB SVG image blocking. + This image has an XML declaration and is expected to load. --> +<meta charset="utf-8"> +<link rel="match" href="img-svg.sub-ref.html"> +<img src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/svg-xml-decl.svg"> diff --git a/testing/web-platform/tests/fetch/corb/img-svg.sub-ref.html b/testing/web-platform/tests/fetch/corb/img-svg.sub-ref.html new file mode 100644 index 0000000000..5462f685a0 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/img-svg.sub-ref.html @@ -0,0 +1,5 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<!-- Same-origin, so the HTTP response is not CORB-eligible. + Serves as reference for cases the image is expected to be loaded. --> +<img src="resources/svg.svg"> diff --git a/testing/web-platform/tests/fetch/corb/preload-image-png-mislabeled-as-html-nosniff.tentative.sub.html b/testing/web-platform/tests/fetch/corb/preload-image-png-mislabeled-as-html-nosniff.tentative.sub.html new file mode 100644 index 0000000000..cea80f2f89 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/preload-image-png-mislabeled-as-html-nosniff.tentative.sub.html @@ -0,0 +1,24 @@ +<!DOCTYPE html> +<!-- This test verifies observable CORB impact on <link rel="preload"> elements. +--> +<meta charset="utf-8"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> + +<script> +async_test(function(t) { + // With CORB the link.onerror event will be reached + // (because CORB will block the cross-origin preload). + window.preloadErrorEvent = t.step_func_done(); + + // Without CORB the link.onload event will be reached. + window.preloadLoadEvent = t.unreached_func("link/preload onload event reached."); +}); +</script> + +<!-- www1 is cross-origin, so the HTTP response is CORB-eligible --> +<link rel="preload" as="image" + onerror="window.preloadErrorEvent()" + onload="window.preloadLoadEvent()" + href="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/png-mislabeled-as-html-nosniff.png"> diff --git a/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html-nosniff.css b/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html-nosniff.css new file mode 100644 index 0000000000..afd2b92975 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html-nosniff.css @@ -0,0 +1 @@ +#header { color: red; } diff --git a/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html-nosniff.css.headers b/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html-nosniff.css.headers new file mode 100644 index 0000000000..0f228f94ec --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html-nosniff.css.headers @@ -0,0 +1,2 @@ +Content-Type: text/html +X-Content-Type-Options: nosniff diff --git a/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html.css b/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html.css new file mode 100644 index 0000000000..afd2b92975 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html.css @@ -0,0 +1 @@ +#header { color: red; } diff --git a/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html.css.headers b/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html.css.headers new file mode 100644 index 0000000000..156209f9c8 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html.css.headers @@ -0,0 +1 @@ +Content-Type: text/html diff --git a/testing/web-platform/tests/fetch/corb/resources/css-with-json-parser-breaker.css b/testing/web-platform/tests/fetch/corb/resources/css-with-json-parser-breaker.css new file mode 100644 index 0000000000..7db6f5c6d3 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/css-with-json-parser-breaker.css @@ -0,0 +1,3 @@ +)]}' +{} +#header { color: red; } diff --git a/testing/web-platform/tests/fetch/corb/resources/empty-labeled-as-png.png b/testing/web-platform/tests/fetch/corb/resources/empty-labeled-as-png.png new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/empty-labeled-as-png.png diff --git a/testing/web-platform/tests/fetch/corb/resources/empty-labeled-as-png.png.headers b/testing/web-platform/tests/fetch/corb/resources/empty-labeled-as-png.png.headers new file mode 100644 index 0000000000..e7be84a714 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/empty-labeled-as-png.png.headers @@ -0,0 +1 @@ +Content-Type: image/png diff --git a/testing/web-platform/tests/fetch/corb/resources/html-correctly-labeled.html b/testing/web-platform/tests/fetch/corb/resources/html-correctly-labeled.html new file mode 100644 index 0000000000..7bad71bfbd --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/html-correctly-labeled.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Page Title</title> + </head> + <body> + <p>Page body</p> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/corb/resources/html-correctly-labeled.html.headers b/testing/web-platform/tests/fetch/corb/resources/html-correctly-labeled.html.headers new file mode 100644 index 0000000000..156209f9c8 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/html-correctly-labeled.html.headers @@ -0,0 +1 @@ +Content-Type: text/html diff --git a/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot.js b/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot.js new file mode 100644 index 0000000000..db45bb4acc --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot.js @@ -0,0 +1,9 @@ +<!--/*--><html><body><script type="text/javascript"><!--//*/ + +// This is a regression test for https://crbug.com/839425 +// which found out that some script resources are served +// with text/html content-type and with a body that is +// both a valid html and a valid javascript. +window['html-js-polyglot.js'] = true; + +//--></script></body></html> diff --git a/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot.js.headers b/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot.js.headers new file mode 100644 index 0000000000..156209f9c8 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot.js.headers @@ -0,0 +1 @@ +Content-Type: text/html diff --git a/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot2.js b/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot2.js new file mode 100644 index 0000000000..faae1b7682 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot2.js @@ -0,0 +1,10 @@ +<!-- comment --> <script type='text/javascript'> +//<![CDATA[ + +// This is a regression test for https://crbug.com/839945 +// which found out that some script resources are served +// with text/html content-type and with a body that is +// both a valid html and a valid javascript. +window['html-js-polyglot2.js'] = true; + +//]]>--></script> diff --git a/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot2.js.headers b/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot2.js.headers new file mode 100644 index 0000000000..156209f9c8 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot2.js.headers @@ -0,0 +1 @@ +Content-Type: text/html diff --git a/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html-nosniff.js b/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html-nosniff.js new file mode 100644 index 0000000000..a880a5bc72 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html-nosniff.js @@ -0,0 +1 @@ +window.has_executed_script = true; diff --git a/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html-nosniff.js.headers b/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html-nosniff.js.headers new file mode 100644 index 0000000000..0f228f94ec --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html-nosniff.js.headers @@ -0,0 +1,2 @@ +Content-Type: text/html +X-Content-Type-Options: nosniff diff --git a/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html.js b/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html.js new file mode 100644 index 0000000000..a880a5bc72 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html.js @@ -0,0 +1 @@ +window.has_executed_script = true; diff --git a/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html.js.headers b/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html.js.headers new file mode 100644 index 0000000000..156209f9c8 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html.js.headers @@ -0,0 +1 @@ +Content-Type: text/html diff --git a/testing/web-platform/tests/fetch/corb/resources/png-correctly-labeled.png b/testing/web-platform/tests/fetch/corb/resources/png-correctly-labeled.png Binary files differnew file mode 100644 index 0000000000..820f8cace2 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/png-correctly-labeled.png diff --git a/testing/web-platform/tests/fetch/corb/resources/png-correctly-labeled.png.headers b/testing/web-platform/tests/fetch/corb/resources/png-correctly-labeled.png.headers new file mode 100644 index 0000000000..e7be84a714 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/png-correctly-labeled.png.headers @@ -0,0 +1 @@ +Content-Type: image/png diff --git a/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html-nosniff.png b/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html-nosniff.png Binary files differnew file mode 100644 index 0000000000..820f8cace2 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html-nosniff.png diff --git a/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html-nosniff.png.headers b/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html-nosniff.png.headers new file mode 100644 index 0000000000..0f228f94ec --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html-nosniff.png.headers @@ -0,0 +1,2 @@ +Content-Type: text/html +X-Content-Type-Options: nosniff diff --git a/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html.png b/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html.png Binary files differnew file mode 100644 index 0000000000..820f8cace2 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html.png diff --git a/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html.png.headers b/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html.png.headers new file mode 100644 index 0000000000..156209f9c8 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html.png.headers @@ -0,0 +1 @@ +Content-Type: text/html diff --git a/testing/web-platform/tests/fetch/corb/resources/response_block_probe.js b/testing/web-platform/tests/fetch/corb/resources/response_block_probe.js new file mode 100644 index 0000000000..9c3b87bcbd --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/response_block_probe.js @@ -0,0 +1 @@ +alert(1); // Arbitrary JavaScript. Details don't matter for the test. diff --git a/testing/web-platform/tests/fetch/corb/resources/response_block_probe.js.headers b/testing/web-platform/tests/fetch/corb/resources/response_block_probe.js.headers new file mode 100644 index 0000000000..0d848b02c2 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/response_block_probe.js.headers @@ -0,0 +1 @@ +Content-Type: text/csv diff --git a/testing/web-platform/tests/fetch/corb/resources/sniffable-resource.py b/testing/web-platform/tests/fetch/corb/resources/sniffable-resource.py new file mode 100644 index 0000000000..f8150936ac --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/sniffable-resource.py @@ -0,0 +1,11 @@ +def main(request, response): + body = request.GET.first(b"body", None) + type = request.GET.first(b"type", None) + + response.add_required_headers = False + response.writer.write_status(200) + response.writer.write_header(b"content-length", len(body)) + response.writer.write_header(b"content-type", type) + response.writer.end_headers() + + response.writer.write(body) diff --git a/testing/web-platform/tests/fetch/corb/resources/subframe-that-posts-html-containing-blob-url-to-parent.html b/testing/web-platform/tests/fetch/corb/resources/subframe-that-posts-html-containing-blob-url-to-parent.html new file mode 100644 index 0000000000..67b3ad5a60 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/subframe-that-posts-html-containing-blob-url-to-parent.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<script> +fetch('html-correctly-labeled.html') + .then(response => response.blob()) + .then(blob => { + let msg = { blob_size: blob.size, + blob_type: blob.type, + blob_url: URL.createObjectURL(blob) }; + window.parent.postMessage(msg, '*'); + }) + .catch(error => { + let msg = { error: error }; + window.parent.postMessage(msg, '*'); + }); +</script> diff --git a/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-empty.svg b/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-empty.svg new file mode 100644 index 0000000000..fa2d29b3b0 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-empty.svg @@ -0,0 +1,4 @@ +<!DOCTYPE html> +<svg width="920" height="625" xmlns="http://www.w3.org/2000/svg" role="img"> +<rect width="100" height="100" style="fill:rgb(255,0,0)"/> +</svg> diff --git a/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-empty.svg.headers b/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-empty.svg.headers new file mode 100644 index 0000000000..29515ee7d4 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-empty.svg.headers @@ -0,0 +1 @@ +Content-Type: diff --git a/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-svg.svg b/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-svg.svg new file mode 100644 index 0000000000..fa2d29b3b0 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-svg.svg @@ -0,0 +1,4 @@ +<!DOCTYPE html> +<svg width="920" height="625" xmlns="http://www.w3.org/2000/svg" role="img"> +<rect width="100" height="100" style="fill:rgb(255,0,0)"/> +</svg> diff --git a/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-svg.svg.headers b/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-svg.svg.headers new file mode 100644 index 0000000000..070de35fbe --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-svg.svg.headers @@ -0,0 +1 @@ +Content-Type: image/svg+xml diff --git a/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-dash.svg b/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-dash.svg new file mode 100644 index 0000000000..2b7d1016b1 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-dash.svg @@ -0,0 +1,3 @@ +<svg width="920" height="625" xmlns="http://www.w3.org/2000/svg" role="img"> +<rect width="100" height="100" style="fill:rgb(255,0,0)"/> +</svg> diff --git a/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-dash.svg.headers b/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-dash.svg.headers new file mode 100644 index 0000000000..43ce612c9f --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-dash.svg.headers @@ -0,0 +1 @@ +Content-Type: application/dash+xml diff --git a/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-svg-xml.svg b/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-svg-xml.svg new file mode 100644 index 0000000000..2b7d1016b1 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-svg-xml.svg @@ -0,0 +1,3 @@ +<svg width="920" height="625" xmlns="http://www.w3.org/2000/svg" role="img"> +<rect width="100" height="100" style="fill:rgb(255,0,0)"/> +</svg> diff --git a/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-svg-xml.svg.headers b/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-svg-xml.svg.headers new file mode 100644 index 0000000000..070de35fbe --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-svg-xml.svg.headers @@ -0,0 +1 @@ +Content-Type: image/svg+xml diff --git a/testing/web-platform/tests/fetch/corb/resources/svg-xml-decl.svg b/testing/web-platform/tests/fetch/corb/resources/svg-xml-decl.svg new file mode 100644 index 0000000000..3b39aff8e5 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/svg-xml-decl.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<svg width="920" height="625" xmlns="http://www.w3.org/2000/svg" role="img"> +<rect width="100" height="100" style="fill:rgb(255,0,0)"/> +</svg> diff --git a/testing/web-platform/tests/fetch/corb/resources/svg.svg b/testing/web-platform/tests/fetch/corb/resources/svg.svg new file mode 100644 index 0000000000..2b7d1016b1 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/svg.svg @@ -0,0 +1,3 @@ +<svg width="920" height="625" xmlns="http://www.w3.org/2000/svg" role="img"> +<rect width="100" height="100" style="fill:rgb(255,0,0)"/> +</svg> diff --git a/testing/web-platform/tests/fetch/corb/resources/svg.svg.headers b/testing/web-platform/tests/fetch/corb/resources/svg.svg.headers new file mode 100644 index 0000000000..070de35fbe --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/resources/svg.svg.headers @@ -0,0 +1 @@ +Content-Type: image/svg+xml diff --git a/testing/web-platform/tests/fetch/corb/response_block.tentative.https.html b/testing/web-platform/tests/fetch/corb/response_block.tentative.https.html new file mode 100644 index 0000000000..6b116000d4 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/response_block.tentative.https.html @@ -0,0 +1,50 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<body> +<script> +// A cross-origin response containing JavaScript, labelled as text/csv. +const probeUrl = get_host_info().HTTPS_REMOTE_ORIGIN + + "/fetch/corb/resources/response_block_probe.js"; + +// Test handling of blocked responses in CORB/ORB for <script> elements. +function probe_script() { + // We will cross-origin load a script resource that should get blocked by all + // versions of CORB/ORB. Two things may happen: + // + // 1, An empty response is injected. (What CORB does.) + // 2, An error is injected and script loading aborts. (What ORB does.) + + // Load the probe as a script. + const script = document.createElement("script"); + script.src = probeUrl; + document.body.appendChild(script); + + // Return a promise that will return a string description corresponding to the + // conditions above. + return new Promise((resolve, reject) => { + script.onload = _ => resolve("Resource loaded (expected for CORB)"); + script.onerror = _ => resolve("ORB-style network error"); + }); +} + +// Test handling of blocked responses in CORB/ORB for script-initiated fetches. +function probe_fetch() { + return fetch(probeUrl, {mode: "no-cors"}) + .then(response => response.text()) + .then(text => { + assert_equals(text, ""); + return "Resource loaded (expected for CORB)"; + }) + .catch(_ => "ORB-style network error"); +} + +// These tests check for ORB behaviour. +promise_test(t => probe_script().then( + value => assert_equals(value, "ORB-style network error")), + "ORB: Expect error response from <script> fetch."); +promise_test(t => probe_fetch().then( + value => assert_equals(value, "ORB-style network error")), + "ORB: Expect error response from fetch()."); +</script> diff --git a/testing/web-platform/tests/fetch/corb/script-html-correctly-labeled.tentative.sub.html b/testing/web-platform/tests/fetch/corb/script-html-correctly-labeled.tentative.sub.html new file mode 100644 index 0000000000..6d1947cea7 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/script-html-correctly-labeled.tentative.sub.html @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<!-- Test verifies that html fed to a <script> tag won't report a syntax + error after CORB blocks the response (an empty response body injected + by CORB won't have any JavaScript syntax errors). +--> +<meta charset="utf-8"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +setup({allow_uncaught_exception : true}); +async_test(function(t) { + var script = document.createElement("script") + + // Without CORB, the html document would cause a syntax error when parsed as + // JavaScript, but with CORB there should be no errors (because CORB will + // replace the response body with an empty body). With ORB, the script loading + // itself will error out. + script.onload = t.step_func_done(); + script.onerror = t.step_func_done(); + addEventListener("error",function(e) { + t.step(function() { + assert_unreached("Empty body of a CORB-blocked response shouldn't trigger syntax errors."); + t.done(); + }) + }); + + // www1 is cross-origin, so the HTTP response is CORB-eligible. + script.src = 'http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/html-correctly-labeled.html'; + document.body.appendChild(script) +}, "CORB-blocked script has no syntax errors"); +</script> diff --git a/testing/web-platform/tests/fetch/corb/script-html-js-polyglot.sub.html b/testing/web-platform/tests/fetch/corb/script-html-js-polyglot.sub.html new file mode 100644 index 0000000000..9a272d63ff --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/script-html-js-polyglot.sub.html @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<!-- Test verifies that CORB won't block a polyglot script that is + both a valid HTML document and also valid Javascript. +--> +<meta charset="utf-8"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> +["html-js-polyglot.js", "html-js-polyglot2.js"].forEach(polyglot_name => { + async_test(function(t) { + window[polyglot_name] = false; + var script = document.createElement("script"); + + script.onload = t.step_func_done(function(){ + // Verify that the script response wasn't blocked - that script + // should have set window[polyglot_name] to true. + assert_true(window[polyglot_name]); + }) + addEventListener("error",function(e) { + t.step(function() { + assert_unreached("No errors are expected with or without CORB."); + t.done(); + }) + }); + + // www1 is cross-origin, so the HTTP response is CORB-eligible. + script.src = "http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/" + polyglot_name; + document.body.appendChild(script); + }, "CORB cannot block polyglot HTML/JS: " + polyglot_name); +}); +</script> diff --git a/testing/web-platform/tests/fetch/corb/script-html-via-cross-origin-blob-url.sub.html b/testing/web-platform/tests/fetch/corb/script-html-via-cross-origin-blob-url.sub.html new file mode 100644 index 0000000000..c8a90c79b3 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/script-html-via-cross-origin-blob-url.sub.html @@ -0,0 +1,38 @@ +<!DOCTYPE html> +<!-- Test verifies that cross-origin blob URIs are blocked both with and + without CORB. +--> +<meta charset="utf-8"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +async_test(function(t) { + function step1_createSubframe() { + addEventListener("message", function(e) { + t.step(function() { step2_processSubframeMsg(e.data); }) + }); + var subframe = document.createElement("iframe") + // www1 is cross-origin, to ensure that the received blob will be cross-origin. + subframe.src = 'http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/subframe-that-posts-html-containing-blob-url-to-parent.html'; + document.body.appendChild(subframe); + } + + function step2_processSubframeMsg(msg) { + assert_false(msg.hasOwnProperty('error'), 'unexpected property found: "error"'); + assert_equals(msg.blob_type, 'text/html'); + assert_equals(msg.blob_size, 147); + + // With and without CORB loading of a cross-origin blob should be blocked + // (this is verified by expecting |script.onerror|, but not |script.onload| + // below). + var script = document.createElement("script") + script.src = msg.blob_url; + script.onerror = t.step_func_done(function(){}) + script.onload = t.unreached_func("Unexpected load event") + document.body.appendChild(script) + } + + step1_createSubframe(); +}); +</script> diff --git a/testing/web-platform/tests/fetch/corb/script-js-mislabeled-as-html-nosniff.sub.html b/testing/web-platform/tests/fetch/corb/script-js-mislabeled-as-html-nosniff.sub.html new file mode 100644 index 0000000000..b6bc90964d --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/script-js-mislabeled-as-html-nosniff.sub.html @@ -0,0 +1,33 @@ +<!DOCTYPE html> +<!-- Test verifies that script mislabeled as html won't execute with and without CORB + if the nosniff response header is present. + + The expected behavior is covered by the Fetch spec at + https://fetch.spec.whatwg.org/#should-response-to-request-be-blocked-due-to-nosniff? + + See also the following tests: + - fetch/nosniff/importscripts.html + - fetch/nosniff/script.html + - fetch/nosniff/worker.html +--> +<meta charset="utf-8"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> + +<script> +setup({ single_test: true }); +window.has_executed_script = false; +</script> + +<!-- www1 is cross-origin, so the HTTP response is CORB-eligible --> +<script src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/js-mislabeled-as-html-nosniff.js"> +</script> + +<script> +// Verify what observable effects the <script> tag above had. +// Assertion should hold with and without CORB: +assert_false(window.has_executed_script, + 'The cross-origin script should not be executed'); +done(); +</script> diff --git a/testing/web-platform/tests/fetch/corb/script-js-mislabeled-as-html.sub.html b/testing/web-platform/tests/fetch/corb/script-js-mislabeled-as-html.sub.html new file mode 100644 index 0000000000..44cb1f8659 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/script-js-mislabeled-as-html.sub.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<!-- Test verifies that script mislabeled as html will execute with and without + CORB (CORB should allow the script after sniffing). +--> +<meta charset="utf-8"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> + +<script> +setup({ single_test: true }); +window.has_executed_script = false; +</script> + +<!-- www1 is cross-origin, so the HTTP response is CORB-eligible --> +<script src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/js-mislabeled-as-html.js"> +</script> + +<script> +// Verify what observable effects the <script> tag above had. +// Assertion should hold with and without CORB: +assert_true(window.has_executed_script, + 'The cross-origin script should execute'); +done(); +</script> diff --git a/testing/web-platform/tests/fetch/corb/script-resource-with-json-parser-breaker.tentative.sub.html b/testing/web-platform/tests/fetch/corb/script-resource-with-json-parser-breaker.tentative.sub.html new file mode 100644 index 0000000000..f0eb1f0ab1 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/script-resource-with-json-parser-breaker.tentative.sub.html @@ -0,0 +1,85 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<!-- Test verifies CORB will block responses beginning with a JSON parser + breaker regardless of their MIME type (excluding text/css - see below). + + A JSON parser breaker is a prefix added to resources with sensitive data to + prevent cross-site script inclusion (XSSI) and similar attacks. For example, + it may be included in JSON files to prevent them from leaking data via a + <script> tag, making the response only useful to a fetch or XmlHttpRequest. + See also https://chromium.googlesource.com/chromium/src/+/main/services/network/cross_origin_read_blocking_explainer.md#Protecting-JSON + + The assumption is that all images, other media, scripts, fonts and other + resources that may be embedded cross-origin will never begin with a JSON + parser breaker. For example an JPEG image should always being with FF D8 FF, + a PNG image with 89 50 4E 47 0D 0A 1A 0A bytes and an SVG image with "<?xml" + substring. + + The assumption above excludes text/css which (as shown by + style-css-with-json-parser-breaker.sub.html) can parse as valid stylesheet + even in presence of a JSON parser breaker. +--> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +setup({allow_uncaught_exception : true}); + +// A subset of JSON security prefixes (only ones that are parser breakers). +json_parser_breakers = [ + ")]}'", + "{}&&", + "{} &&", +] + +// JSON parser breaker should trigger CORB blocking for any Content-Type - even +// for resources that claim to be of a MIME type that is normally allowed to be +// embedded in cross-origin documents (like images and/or scripts). +mime_types = [ + // CORB-protected MIME types + "text/html", + "text/xml", + "text/json", + "text/plain", + + // MIME types that normally are allowed by CORB. + "application/javascript", + "image/png", + "image/svg+xml", + + // Other types. + "application/pdf", + "application/zip", +] + +function test(mime_type, body) { + // The test below depends on a global/shared event handler - we need to ensure + // that no tests run in parallel - this is achieved by using `promise_test` + // instead of `async_test`. See also + // https://web-platform-tests.org/writing-tests/testharness-api.html#promise-tests + promise_test(t => new Promise(function(resolve, reject) { + var script = document.createElement("script") + + // Without CORB, the JSON parser breaker would cause a syntax error when + // parsed as JavaScript, but with CORB there should be no errors (because + // CORB will replace the response body with an empty body). With ORB, + // the script loading itself should error out. + script.onload = resolve; + script.onerror = resolve; + addEventListener("error", t.unreached_func( + "Empty body of a CORS-blocked response shouldn't trigger syntax errors.")) + + // www1 is cross-origin, so the HTTP response is CORB-eligible. + var src_prefix = "http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/sniffable-resource.py"; + script.src = src_prefix + "?type=" + mime_type + "&body=" + encodeURIComponent(body); + document.body.appendChild(script) + }), "CORB-blocks '" + mime_type + "' that starts with the following JSON parser breaker: " + body); +} + +mime_types.forEach(function(type) { + json_parser_breakers.forEach(function(body) { + test(type, body); + }); +}); + +</script> diff --git a/testing/web-platform/tests/fetch/corb/script-resource-with-nonsniffable-types.tentative.sub.html b/testing/web-platform/tests/fetch/corb/script-resource-with-nonsniffable-types.tentative.sub.html new file mode 100644 index 0000000000..6d490d55bc --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/script-resource-with-nonsniffable-types.tentative.sub.html @@ -0,0 +1,84 @@ +<!DOCTYPE html> +<!-- Test verifies CORB will block responses with types that do not + require confirmation sniffing. + + We assume that: + 1) it is unlikely that images, other media, scripts, etc. will be mislabelled + as the |protected_mime_types| below, + 2) the |protected_mime_types| below are likely to contain sensitive, + credentialled data. +--> +<meta charset="utf-8"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/utils.js"></script> +<div id=log></div> +<script> +setup({allow_uncaught_exception : true, single_test : true}); + +function test(mime_type, is_blocking_expected) { + var action = is_blocking_expected ? "blocks" : "does not block"; + + async_test(function(t) { + var script = document.createElement("script") + var script_has_run_token = "script_has_run" + token(); + + // With and without CORB there should be no error, but without CORB the + // original script body will be preserved and |window.script_has_run| will + // be set. + window[script_has_run_token] = false; + script.onload = t.step_func_done(function(){ + if (is_blocking_expected) { + assert_false(window[script_has_run_token]); + } else { + assert_true(window[script_has_run_token]); + } + }); + addEventListener("error",function(e) { + t.step(function() { + assert_unreached("Unexpected error: " + e); + t.done(); + }) + }); + + // www1 is cross-origin, so the HTTP response is CORB-eligible. + var src_prefix = "http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/sniffable-resource.py"; + body = `window['${script_has_run_token}'] = true;` + script.src = src_prefix + "?type=" + mime_type + "&body=" + encodeURIComponent(body); + document.body.appendChild(script) + }, "CORB " + action + " '" + mime_type + "'"); +} + +// Some mime types should be protected by CORB without any kind +// of confirmation sniffing. +protected_mime_types = [ + "application/gzip", + "application/pdf", + "application/x-gzip", + "application/x-protobuf", + "application/zip", + "multipart/byteranges", + "multipart/signed", + "text/csv", + "text/event-stream", +] +protected_mime_types.forEach(function(type) { + test(type, true /* is_blocking_expected */); +}); + +// Other mime types. +other_mime_types = [ + // These content types are legitimately allowed in 'no-cors' fetches. + "application/javascript", + + // Confirmation sniffing will fail and prevent CORB from blocking the + // response. + "text/html", + + // Unrecognized content types. + "application/blah" +] +other_mime_types.forEach(function(type) { + test(type, false /* is_blocking_expected */); +}); +</script> diff --git a/testing/web-platform/tests/fetch/corb/style-css-mislabeled-as-html-nosniff.sub.html b/testing/web-platform/tests/fetch/corb/style-css-mislabeled-as-html-nosniff.sub.html new file mode 100644 index 0000000000..8fef0dc59e --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/style-css-mislabeled-as-html-nosniff.sub.html @@ -0,0 +1,42 @@ +<!DOCTYPE html> +<!-- Test verifies that a stylesheet mislabeled as html won't execute with and + without CORB if the nosniff response header is present. + + The expected behavior is covered by the Fetch spec at + https://fetch.spec.whatwg.org/#should-response-to-request-be-blocked-due-to-nosniff? + + See also the following tests: + - fetch/nosniff/stylesheet.html +--> +<meta charset="utf-8"> +<title>CSS is not applied (because of nosniff + non-text/css headers)</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> + +<!-- Default style that will be applied if the external stylesheet resource + below won't load for any reason. This stylesheet will set h1's + color to green (see |default_color| below). --> +<style> +h1 { color: green; } +</style> + +<!-- This stylesheet (if loaded) should set h1#header's color to red + (see |external_color| below). --> +<!-- www1 is cross-origin, so the HTTP response is CORB-eligible --> +<link rel="stylesheet" type="text/css" + href="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/css-mislabeled-as-html-nosniff.css"> + +<body> + <h1 id="header">Header example</h1> + <p>Paragraph body</p> +</body> + +<script> +test(() => { + let style = getComputedStyle(document.getElementById('header')); + const external_color = 'rgb(255, 0, 0)'; // red + const default_color = 'rgb(0, 128, 0)'; // green + assert_equals(style.getPropertyValue('color'), default_color); + assert_not_equals(style.getPropertyValue('color'), external_color); +}); +</script> diff --git a/testing/web-platform/tests/fetch/corb/style-css-mislabeled-as-html.sub.html b/testing/web-platform/tests/fetch/corb/style-css-mislabeled-as-html.sub.html new file mode 100644 index 0000000000..4f0b4c22f5 --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/style-css-mislabeled-as-html.sub.html @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<!-- Test verifies that CORB won't impact a cross-origin stylesheet mislabeled + as text/html (because even without CORB mislabeled CSS will be rejected). +--> +<meta charset="utf-8"> +<title>CSS is not applied (because of strict content-type enforcement for cross-origin stylesheets)</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> + +<!-- Default style that will be applied if the external stylesheet resource + below won't load for any reason. This stylesheet will set h1's + color to green (see |default_color| below). --> +<style> +h1 { color: green; } +</style> + +<!-- This stylesheet (if loaded) should set h1#header's color to red + (see |external_color| below). --> +<!-- www1 is cross-origin, so the HTTP response is CORB-eligible --> +<link rel="stylesheet" type="text/css" + href="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/css-mislabeled-as-html.css"> + +<body> + <h1 id="header">Header example</h1> + <p>Paragraph body</p> +</body> + +<script> +test(() => { + let style = getComputedStyle(document.getElementById('header')); + const external_color = 'rgb(255, 0, 0)'; // red + const default_color = 'rgb(0, 128, 0)'; // green + assert_equals(style.getPropertyValue('color'), default_color); + assert_not_equals(style.getPropertyValue('color'), external_color); +}); +</script> diff --git a/testing/web-platform/tests/fetch/corb/style-css-with-json-parser-breaker.sub.html b/testing/web-platform/tests/fetch/corb/style-css-with-json-parser-breaker.sub.html new file mode 100644 index 0000000000..29ed586a4f --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/style-css-with-json-parser-breaker.sub.html @@ -0,0 +1,38 @@ +<!DOCTYPE html> +<!-- Test verifies that CORB won't block a stylesheet that + 1) is correctly labeled with text/css Content-Type and parsing fine as text/css + 2) starts with a JSON parser breaker (like )]}') +--> +<meta charset="utf-8"> +<title>CORB doesn't block a stylesheet that has a proper Content-Type and begins with a JSON parser breaker</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> + +<!-- Default style that will be applied if the external stylesheet resource + below won't load for any reason. This stylesheet will set h1's + color to green (see |default_color| below). --> +<style> +h1 { color: green; } +</style> + +<!-- This stylesheet (if loaded) should set h1#header's color to red + (see |external_color| below). --> +<!-- www1 is cross-origin, so the HTTP response is CORB-eligible --> +<link rel="stylesheet" type="text/css" + href="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/css-with-json-parser-breaker.css"> + +<body> + <h1 id="header">Header example</h1> + <p>Paragraph body</p> +</body> + +<script> +test(() => { + // Verify that CSS got applied / did not get blocked by CORB. + let style = getComputedStyle(document.getElementById('header')); + const external_color = 'rgb(255, 0, 0)'; // red + const default_color = 'rgb(0, 128, 0)'; // green + assert_equals(style.getPropertyValue('color'), external_color); + assert_not_equals(style.getPropertyValue('color'), default_color); +}); +</script> diff --git a/testing/web-platform/tests/fetch/corb/style-html-correctly-labeled.sub.html b/testing/web-platform/tests/fetch/corb/style-html-correctly-labeled.sub.html new file mode 100644 index 0000000000..cdefcd2d2c --- /dev/null +++ b/testing/web-platform/tests/fetch/corb/style-html-correctly-labeled.sub.html @@ -0,0 +1,41 @@ +<!DOCTYPE html> +<!-- Test verifies that using a HTML document as a stylesheet has no observable + differences with and without CORB: + - The cross-origin stylesheet requires a correct text/css Content-Type + and therefore won't render even without CORB. This aspect of this test + is similar to the style-css-mislabeled-as-html.sub.html test. + - Even if the Content-Type requirements were relaxed for cross-origin stylesheets, + the HTML document is unlikely to parse as a stylesheet (unless a polyglot + HTML/CSS document is crafted as part of an attack) and therefore the + observable behavior should be indistinguishable from parsing the empty, + CORB-blocked response as a stylesheet. +--> +<meta charset="utf-8"> +<title>CSS is not applied (because of mismatched Content-Type header)</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> + +<!-- Default style that will be applied if the external stylesheet resource + below won't load for any reason. This stylesheet will set h1's + color to green (see |default_color| below). --> +<style> +h1 { color: green; } +</style> + +<!-- This is not really a stylesheet... --> +<!-- www1 is cross-origin, so the HTTP response is CORB-eligible --> +<link rel="stylesheet" type="text/css" + href="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/html-correctly-labeled.html"> + +<body> + <h1 id="header">Header example</h1> + <p>Paragraph body</p> +</body> + +<script> +test(() => { + var style = getComputedStyle(document.getElementById('header')); + const default_color = 'rgb(0, 128, 0)'; // green + assert_equals(style.getPropertyValue('color'), default_color); +}); +</script> |