diff options
Diffstat (limited to 'testing/web-platform/tests/content-security-policy/securitypolicyviolation')
28 files changed, 1334 insertions, 0 deletions
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-eval.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-eval.html new file mode 100644 index 0000000000..ddd5068df1 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-eval.html @@ -0,0 +1,20 @@ +<!doctype html> +<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + async_test(t => { + var watcher = new EventWatcher(t, document, 'securitypolicyviolation'); + watcher.wait_for('securitypolicyviolation').then(t.step_func_done(e => { + assert_equals(e.blockedURI, "eval"); + assert_equals(e.lineNumber, 15); + assert_equals(e.columnNumber, 12); + })); + + try { + eval("assert_unreached('eval() should be blocked."); + } catch (e) { + assert_equals(e.name, 'EvalError'); + } + }, "Eval violations have a blockedURI of 'eval'"); +</script> diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-inline.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-inline.html new file mode 100644 index 0000000000..40c4865185 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-inline.html @@ -0,0 +1,19 @@ +<!doctype html> +<meta http-equiv="Content-Security-Policy" content="script-src 'nonce-abc'"> +<script nonce="abc" src="/resources/testharness.js"></script> +<script nonce="abc" src="/resources/testharnessreport.js"></script> +<script nonce="abc"> + async_test(t => { + var watcher = new EventWatcher(t, document, 'securitypolicyviolation'); + watcher.wait_for('securitypolicyviolation').then(t.step_func_done(e => { + assert_equals(e.blockedURI, "inline"); + assert_equals(e.lineNumber, 15); + assert_equals(e.columnNumber, 1); + })); + }, "Inline violations have a blockedURI of 'inline'"); +</script> +<script> + test(t => { + assert_unreached(); + }, "Blocked script shouldn't execute."); +</script> diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-ws-wss-scheme.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-ws-wss-scheme.html new file mode 100644 index 0000000000..88bf4ae599 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-ws-wss-scheme.html @@ -0,0 +1,53 @@ +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script> + +const info = get_host_info(); + +const nextCSPViolation = (test) => { + return new Promise((resolve, reject) => { + document.addEventListener("securitypolicyviolation", resolve, {once: true}); + test.step_timeout(() => reject("timeout"), 3000); + }); +}; + +const redirector = get_host_info().HTTP_REMOTE_ORIGIN.replace("http", "wss") + + "/common/redirect.py"; + +promise_setup(async () => { + const meta = document.createElement('meta'); + meta.httpEquiv = "Content-Security-Policy"; + meta.content = "connect-src " + redirector; + document.getElementsByTagName('head')[0].appendChild(meta); +}, "Install <meta> CSP"); + +promise_test(async test => { + const url = get_host_info().HTTP_ORIGIN.replace("http", "ws") + "/path"; + const violation = nextCSPViolation(test); + try { new WebSocket(url); } catch (e) {} + assert_equals((await violation).blockedURI, url); +}, "ws"); + +promise_test(async test => { + const url = get_host_info().HTTP_ORIGIN.replace("http", "wss") + "/path"; + const violation = nextCSPViolation(test); + try { new WebSocket(url); } catch (e) {} + assert_equals((await violation).blockedURI, url); +}, "wss"); + +promise_test(async test => { + const url = get_host_info().HTTP_REMOTE_ORIGIN.replace("http", "wss") + "/path"; + const violation = nextCSPViolation(test); + try { new WebSocket(url); } catch (e) {} + assert_equals((await violation).blockedURI, url); +}, "cross-origin"); + +promise_test(async test => { + const url = get_host_info().HTTP_ORIGIN.replace("http", "wss") + "/path"; + const violation = nextCSPViolation(test); + try {new WebSocket(redirector + "?location=" + url); } catch (e) {} + assert_equals((await violation).blockedURI, url); +}, "redirect"); + +</script> diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/constructor-required-fields.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/constructor-required-fields.html new file mode 100644 index 0000000000..1a090d8e2c --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/constructor-required-fields.html @@ -0,0 +1,239 @@ +<!doctype html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + // basic tests. + test(function() { + assert_throws_js(TypeError, + function() { new SecurityPolicyViolationEvent(); }); + }, "SecurityPolicyViolationEvent constructor should throw with no parameters"); + + test(function() { + assert_not_equals(new SecurityPolicyViolationEvent("securitypolicyviolation", { + documentURI: "http://example.com", + referrer: "http://example.com", + blockedURI: "http://example.com", + violatedDirective: "default-src", + effectiveDirective: "default-src", + originalPolicy: "default-src 'none'", + sourceFile: "example.js", + sample: "<script>alert('1');</scr" + "ipt>", + disposition: "enforce", + statusCode: 200, + lineNumber: 1, + columnNumber: 1, + }), undefined); + }, "SecurityPolicyViolationEvent constructor works with an init dict"); + + // missing required members + test(function() { + assert_throws_js(TypeError, + function() { new SecurityPolicyViolationEvent("securitypolicyviolation", { + // documentURI: "http://example.com", + referrer: "http://example.com", + blockedURI: "http://example.com", + violatedDirective: "default-src", + effectiveDirective: "default-src", + originalPolicy: "default-src 'none'", + sourceFile: "example.js", + sample: "<script>alert('1');</scr" + "ipt>", + disposition: "enforce", + statusCode: 200, + lineNumber: 1, + columnNumber: 1, + })}); + }, "SecurityPolicyViolationEvent constructor requires documentURI"); + + test(function() { + assert_throws_js(TypeError, + function() { new SecurityPolicyViolationEvent("securitypolicyviolation", { + documentURI: "http://example.com", + referrer: "http://example.com", + blockedURI: "http://example.com", + // violatedDirective: "default-src", + effectiveDirective: "default-src", + originalPolicy: "default-src 'none'", + sourceFile: "example.js", + sample: "<script>alert('1');</scr" + "ipt>", + disposition: "enforce", + statusCode: 200, + lineNumber: 1, + columnNumber: 1, + })}); + }, "SecurityPolicyViolationEvent constructor requires violatedDirective"); + + test(function() { + assert_throws_js(TypeError, + function() { new SecurityPolicyViolationEvent("securitypolicyviolation", { + documentURI: "http://example.com", + referrer: "http://example.com", + blockedURI: "http://example.com", + violatedDirective: "default-src", + // effectiveDirective: "default-src", + originalPolicy: "default-src 'none'", + sourceFile: "example.js", + sample: "<script>alert('1');</scr" + "ipt>", + disposition: "enforce", + statusCode: 200, + lineNumber: 1, + columnNumber: 1, + })}); + }, "SecurityPolicyViolationEvent constructor requires effectiveDirective"); + + test(function() { + assert_throws_js(TypeError, + function() { new SecurityPolicyViolationEvent("securitypolicyviolation", { + documentURI: "http://example.com", + referrer: "http://example.com", + blockedURI: "http://example.com", + violatedDirective: "default-src", + effectiveDirective: "default-src", + // originalPolicy: "default-src 'none'", + sourceFile: "example.js", + sample: "<script>alert('1');</scr" + "ipt>", + disposition: "enforce", + statusCode: 200, + lineNumber: 1, + columnNumber: 1, + })}); + }, "SecurityPolicyViolationEvent constructor requires originalPolicy"); + + test(function() { + assert_throws_js(TypeError, + function() { new SecurityPolicyViolationEvent("securitypolicyviolation", { + documentURI: "http://example.com", + referrer: "http://example.com", + blockedURI: "http://example.com", + violatedDirective: "default-src", + effectiveDirective: "default-src", + originalPolicy: "default-src 'none'", + sourceFile: "example.js", + sample: "<script>alert('1');</scr" + "ipt>", + // disposition: "enforce", + statusCode: 200, + lineNumber: 1, + columnNumber: 1, + })}); + }, "SecurityPolicyViolationEvent constructor requires disposition"); + + test(function() { + assert_throws_js(TypeError, + function() { new SecurityPolicyViolationEvent("securitypolicyviolation", { + documentURI: "http://example.com", + referrer: "http://example.com", + blockedURI: "http://example.com", + violatedDirective: "default-src", + effectiveDirective: "default-src", + originalPolicy: "default-src 'none'", + sourceFile: "example.js", + sample: "<script>alert('1');</scr" + "ipt>", + disposition: "enforce", + // statusCode: 200, + lineNumber: 1, + columnNumber: 1, + })}); + }, "SecurityPolicyViolationEvent constructor requires statusCode"); + + // missing optional members + test(function() { + assert_not_equals(new SecurityPolicyViolationEvent("securitypolicyviolation", { + documentURI: "http://example.com", + // referrer: "http://example.com", + blockedURI: "http://example.com", + violatedDirective: "default-src", + effectiveDirective: "default-src", + originalPolicy: "default-src 'none'", + sourceFile: "example.js", + sample: "<script>alert('1');</scr" + "ipt>", + disposition: "enforce", + statusCode: 200, + lineNumber: 1, + columnNumber: 1, + }), undefined); + }, "SecurityPolicyViolationEvent constructor does not require referrer"); + + test(function() { + assert_not_equals(new SecurityPolicyViolationEvent("securitypolicyviolation", { + documentURI: "http://example.com", + referrer: "http://example.com", + // blockedURI: "http://example.com", + violatedDirective: "default-src", + effectiveDirective: "default-src", + originalPolicy: "default-src 'none'", + sourceFile: "example.js", + sample: "<script>alert('1');</scr" + "ipt>", + disposition: "enforce", + statusCode: 200, + lineNumber: 1, + columnNumber: 1, + }), undefined); + }, "SecurityPolicyViolationEvent constructor does not require blockedURI"); + + test(function() { + assert_not_equals(new SecurityPolicyViolationEvent("securitypolicyviolation", { + documentURI: "http://example.com", + referrer: "http://example.com", + blockedURI: "http://example.com", + violatedDirective: "default-src", + effectiveDirective: "default-src", + originalPolicy: "default-src 'none'", + // sourceFile: "example.js", + sample: "<script>alert('1');</scr" + "ipt>", + disposition: "enforce", + statusCode: 200, + lineNumber: 1, + columnNumber: 1, + }), undefined); + }, "SecurityPolicyViolationEvent constructor does not require sourceFile"); + + test(function() { + assert_not_equals(new SecurityPolicyViolationEvent("securitypolicyviolation", { + documentURI: "http://example.com", + referrer: "http://example.com", + blockedURI: "http://example.com", + violatedDirective: "default-src", + effectiveDirective: "default-src", + originalPolicy: "default-src 'none'", + sourceFile: "example.js", + // sample: "<script>alert('1');</scr" + "ipt>", + disposition: "enforce", + statusCode: 200, + lineNumber: 1, + columnNumber: 1, + }), undefined); + }, "SecurityPolicyViolationEvent constructor does not require sample"); + + test(function() { + assert_not_equals(new SecurityPolicyViolationEvent("securitypolicyviolation", { + documentURI: "http://example.com", + referrer: "http://example.com", + blockedURI: "http://example.com", + violatedDirective: "default-src", + effectiveDirective: "default-src", + originalPolicy: "default-src 'none'", + sourceFile: "example.js", + sample: "<script>alert('1');</scr" + "ipt>", + disposition: "enforce", + statusCode: 200, + // lineNumber: 1, + columnNumber: 1, + }), undefined); + }, "SecurityPolicyViolationEvent constructor does not require lineNumber"); + + test(function() { + assert_not_equals(new SecurityPolicyViolationEvent("securitypolicyviolation", { + documentURI: "http://example.com", + referrer: "http://example.com", + blockedURI: "http://example.com", + violatedDirective: "default-src", + effectiveDirective: "default-src", + originalPolicy: "default-src 'none'", + sourceFile: "example.js", + sample: "<script>alert('1');</scr" + "ipt>", + disposition: "enforce", + statusCode: 200, + lineNumber: 1, + // columnNumber: 1, + }), undefined); + }, "SecurityPolicyViolationEvent constructor does not require columnNumber"); +</script> diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/idlharness.window.js b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/idlharness.window.js new file mode 100644 index 0000000000..25efd0d4e1 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/idlharness.window.js @@ -0,0 +1,18 @@ +// META: script=/resources/WebIDLParser.js +// META: script=/resources/idlharness.js + +// https://w3c.github.io/webappsec-csp/ + +'use strict'; + +idl_test( + ['CSP'], + ['dom', 'reporting'], + idl_array => { + idl_array.add_objects({ + SecurityPolicyViolationEvent: [ + 'new SecurityPolicyViolationEvent("securitypolicyviolation")' + ] + }) + } +); diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html new file mode 100644 index 0000000000..c63206db46 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html @@ -0,0 +1,31 @@ +<!doctype html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="./support/testharness-helper.sub.js"></script> +<body></body> +<script> + function waitForViolation(el, t, policy, blockedURI) { + return new Promise(resolve => { + el.addEventListener('securitypolicyviolation', e => { + if (e.originalPolicy == policy && e.blockedURI == blockedURI) + resolve(e); + else + t.unreached_func("Unexpected violation event for " + e.blockedURI)(); + }); + }); + } + + async_test(t => { + var i = document.createElement("img"); + var redirect = generateCrossOriginRedirectImage(); + i.src = redirect.url; + + // Report-only policy should trigger a violation on the redirected request. + waitForViolation(window, t, "img-src https:", new URL(redirect.url, window.location).href).then(t.step_func(e => { + t.done(); + })); + + document.body.appendChild(i); + }, "Image that redirects to http:// URL prohibited by Report-Only must generate a violation report, even with upgrade-insecure-requests"); +</script> +</html> diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html.headers b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html.headers new file mode 100644 index 0000000000..57207bbd23 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html.headers @@ -0,0 +1,2 @@ +Content-Security-Policy-Report-Only: img-src https: +Content-Security-Policy: upgrade-insecure-requests diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect.sub.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect.sub.html new file mode 100644 index 0000000000..9bffad09b3 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect.sub.html @@ -0,0 +1,25 @@ +<!doctype html> +<meta http-equiv="content-security-policy" content="img-src 'self'"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body></body> +<script> + async_test(t => { + const i = document.createElement("img"); + + const target = "http://{{hosts[alt][]}}:{{ports[http][0]}}/content-security-policy/support/fail.png"; + const url = window.origin + "/common/redirect.py?location=" + encodeURIComponent(target); + + window.addEventListener('securitypolicyviolation', t.step_func_done((e) => { + assert_equals(e.blockedURI, url); + })); + + i.onload = t.step_func(() => { + assert_unreached("Img should be blocked."); + }); + i.src = url; + + document.body.appendChild(i); + }, "The blocked URI in the security policy violation event should be the original URI before redirects."); +</script> +</html> diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/inside-dedicated-worker.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/inside-dedicated-worker.html new file mode 100644 index 0000000000..0912ec2ad9 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/inside-dedicated-worker.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<!-- + Set a policy in the document to ensure that the block is triggering + in the worker and not in the document. +--> +<meta http-equiv="content-security-policy" content="connect-src 'self'"> + +<script> + var w = new Worker("./support/inside-worker.sub.js"); + + // Forward 'securitypolicyviolation' events from the document into the + // worker (we shouldn't actually see any, so the worker will assert that + // none are fired). + document.addEventListener('securitypolicyviolation', _ => { + w.postMessage("SecurityPolicyViolation from Document"); + }); + + fetch_tests_from_worker(w); +</script> diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/inside-service-worker.https.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/inside-service-worker.https.html new file mode 100644 index 0000000000..e0e59c8b8e --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/inside-service-worker.https.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<!-- + Set a policy in the document to ensure that the block is triggering + in the worker and not in the document. +--> +<meta http-equiv="content-security-policy" content="connect-src 'self'"> + +<script> + navigator.serviceWorker.register("./support/inside-worker.sub.js", { scope: "./support/" }) + .then(r => { + var sw = r.active || r.installing || r.waiting; + add_completion_callback(_ => r.unregister()); + + // Forward 'securitypolicyviolation' events from the document into the + // worker (we shouldn't actually see any, so the worker will assert that + // none are fired. + document.addEventListener('securitypolicyviolation', _ => { + sw.postMessage("SecurityPolicyViolation from Document"); + }); + + fetch_tests_from_worker(sw); + }); +</script> + diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/inside-shared-worker.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/inside-shared-worker.html new file mode 100644 index 0000000000..4fddf12a3c --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/inside-shared-worker.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<!-- + Set a policy in the document to ensure that the block is triggering + in the worker and not in the document. +--> +<meta http-equiv="content-security-policy" content="connect-src 'self'"> + +<script> + var w = new SharedWorker("./support/inside-worker.sub.js"); + + // Forward 'securitypolicyviolation' events from the document into the + // worker (we shouldn't actually see any, so the worker will assert that + // none are fired. + document.addEventListener('securitypolicyviolation', _ => { + w.port.postMessage("SecurityPolicyViolation from Document"); + }); + + fetch_tests_from_worker(w); +</script> + diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/script-sample-no-opt-in.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/script-sample-no-opt-in.html new file mode 100644 index 0000000000..3e25ce299c --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/script-sample-no-opt-in.html @@ -0,0 +1,80 @@ +<!doctype html> +<meta http-equiv="Content-Security-Policy" content="script-src 'nonce-abc'; style-src 'self'; img-src 'none'"> +<script nonce="abc" src="/resources/testharness.js"></script> +<script nonce="abc" src="/resources/testharnessreport.js"></script> +<body> +<script nonce="abc"> + function waitForViolation(el) { + return new Promise(resolve => { + el.addEventListener('securitypolicyviolation', e => resolve(e)); + }); + } + + async_test(t => { + var s = document.createElement('script'); + s.innerText = "assert_unreached('inline script block')"; + + waitForViolation(s) + .then(t.step_func_done(e => { + assert_equals(e.blockedURI, "inline"); + assert_equals(e.sample, ""); + })); + + document.head.append(s); + }, "Inline script should not have a sample."); + + async_test(t => { + var a = document.createElement("a"); + a.setAttribute("onclick", "assert_unreached('inline event handler')"); + + waitForViolation(a) + .then(t.step_func_done(e => { + assert_equals(e.blockedURI, "inline"); + assert_equals(e.sample, ""); + })); + + document.body.append(a); + a.click(); + }, "Inline event handlers should not have a sample."); + + async_test(t => { + var i = document.createElement("iframe"); + i.src = "javascript:'inline url'"; + + waitForViolation(i) + .then(t.step_func_done(e => { + assert_equals(e.blockedURI, "inline"); + assert_equals(e.sample, ""); + })); + + document.body.append(i); + }, "JavaScript URLs in iframes should not have a sample."); + + async_test(t => { + var violations = 0; + document.addEventListener('securitypolicyviolation', t.step_func(e => { + if (e.blockedURI != "eval") + return; + + assert_equals(e.sample, ""); + violations++ + if (violations == 3) + t.done(); + })); + try { + eval("assert_unreached('eval')"); + assert_unreached('eval'); + } catch (e) { + } + try { + setInterval("assert_unreached('interval')", 1000); + assert_unreached('interval'); + } catch (e) { + } + try { + setTimeout("assert_unreached('timeout')", 1000); + assert_unreached('timeout'); + } catch (e) { + } + }, "eval()-alikes should not have a sample."); +</script> diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/script-sample.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/script-sample.html new file mode 100644 index 0000000000..b38055bf7b --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/script-sample.html @@ -0,0 +1,94 @@ +<!doctype html> +<meta http-equiv="Content-Security-Policy" content="script-src 'nonce-abc' 'report-sample'; style-src 'self'; img-src 'none'"> +<script nonce="abc" src="/resources/testharness.js"></script> +<script nonce="abc" src="/resources/testharnessreport.js"></script> +<body> +<script nonce="abc"> + function waitForViolation(el) { + return new Promise(resolve => { + el.addEventListener('securitypolicyviolation', e => resolve(e)); + }); + } + + async_test(t => { + var s = document.createElement('script'); + s.innerText = "assert_unreached('inline script block')"; + + waitForViolation(s) + .then(t.step_func_done(e => { + assert_equals(e.blockedURI, "inline"); + assert_equals(e.sample, "assert_unreached('inline script block')"); + })); + + document.head.append(s); + }, "Inline script should have a sample."); + + async_test(t => { + var a = document.createElement("a"); + a.setAttribute("onclick", "assert_unreached('inline event handler')"); + + waitForViolation(a) + .then(t.step_func_done(e => { + assert_equals(e.blockedURI, "inline"); + assert_equals(e.sample, "assert_unreached('inline event handler')"); + })); + + document.body.append(a); + a.click(); + }, "Inline event handlers should have a sample."); + + async_test(t => { + var i = document.createElement("iframe"); + i.src = "javascript:'inline url'"; + + waitForViolation(i) + .then(t.step_func_done(e => { + assert_equals(e.blockedURI, "inline"); + assert_equals(e.sample, "javascript:'inline url'"); + })); + + document.body.append(i); + }, "JavaScript URLs in iframes should have a sample."); + + async_test(t => { + document.addEventListener('securitypolicyviolation', t.step_func(e => { + if (e.blockedURI == "eval" && + e.sample == "assert_unreached('eval')") { + t.done(); + } + })); + try { + eval("assert_unreached('eval')"); + assert_unreached('eval'); + } catch (e) { + } + }, "eval() should have a sample."); + + async_test(t => { + document.addEventListener('securitypolicyviolation', t.step_func(e => { + if (e.blockedURI == "eval" && + e.sample == "assert_unreached('interval')") { + t.done(); + } + })); + try { + setInterval("assert_unreached('interval')", 1000); + assert_unreached('interval'); + } catch (e) { + } + }, "setInterval() should have a sample."); + + async_test(t => { + document.addEventListener('securitypolicyviolation', t.step_func(e => { + if (e.blockedURI == "eval" && + e.sample == "assert_unreached('timeout')") { + t.done(); + } + })); + try { + setTimeout("assert_unreached('timeout')", 1000); + assert_unreached('timeout'); + } catch (e) { + } + }, "setTimeout() should have a sample."); +</script> diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub.html new file mode 100644 index 0000000000..318fae4634 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub.html @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/content-security-policy/support/testharness-helper.js"></script> +<meta http-equiv="Content-Security-Policy" content="img-src 'none'"> +<body> +<script> + async_test(t => { + waitUntilEvent(window, "securitypolicyviolation") + .then(t.step_func_done(e => { + assert_equals(e.documentURI, document.location.toString()); + assert_equals(e.referrer, document.referrer); + assert_equals(e.blockedURI, "http://{{domains[www]}}:{{ports[http][0]}}/content-security-policy/support/fail.png"); + assert_equals(e.violatedDirective, "img-src"); + assert_equals(e.effectiveDirective, "img-src"); + assert_equals(e.originalPolicy, "img-src \'none\'"); + assert_equals(e.disposition, "enforce"); + assert_equals(new URL(e.sourceFile).pathname, "/content-security-policy/support/inject-image.sub.js"); + assert_equals(e.lineNumber, 2); + assert_equals(e.columnNumber, 0); + assert_equals(e.statusCode, 200); + })); + + var s = document.createElement("script"); + s.src = "{{location[scheme]}}://{{domains[www2]}}:{{location[port]}}/content-security-policy/support/inject-image.sub.js"; + document.body.appendChild(s); + }, "Non-redirected cross-origin URLs are not stripped."); +</script> diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html new file mode 100644 index 0000000000..44ca8d50e4 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/content-security-policy/support/testharness-helper.js"></script> +<meta http-equiv="Content-Security-Policy" content="img-src 'none'"> +<body> +<script> + async_test(t => { + waitUntilEvent(window, "securitypolicyviolation") + .then(t.step_func_done(e => { + assert_equals(e.documentURI, document.location.toString()); + assert_equals(e.referrer, document.referrer); + assert_equals(e.blockedURI, "{{location[scheme]}}://{{domains[www]}}:{{location[port]}}/content-security-policy/support/fail.png"); + assert_equals(e.violatedDirective, "img-src"); + assert_equals(e.effectiveDirective, "img-src"); + assert_equals(e.originalPolicy, "img-src \'none\'"); + assert_equals(e.disposition, "enforce"); + assert_equals(new URL(e.sourceFile).pathname, "/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html"); + assert_equals(e.lineNumber, 25); + assert_equals(e.columnNumber, 4); + assert_equals(e.statusCode, 200); + })); + + var i = document.createElement("img"); + i.src = "{{location[scheme]}}://{{domains[www]}}:{{location[port]}}/content-security-policy/support/fail.png"; + }, "Non-redirected cross-origin URLs are not stripped."); +</script> diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub.html new file mode 100644 index 0000000000..c09643c20e --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub.html @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/content-security-policy/support/testharness-helper.js"></script> +<meta http-equiv="Content-Security-Policy" content="img-src 'none'"> +<body> +<script> + async_test(t => { + waitUntilEvent(window, "securitypolicyviolation") + .then(t.step_func_done(e => { + assert_equals(e.documentURI, document.location.toString()); + assert_equals(e.referrer, document.referrer); + assert_equals(e.blockedURI, "http://{{domains[www]}}:{{ports[http][0]}}/content-security-policy/support/fail.png"); + assert_equals(e.violatedDirective, "img-src"); + assert_equals(e.effectiveDirective, "img-src"); + assert_equals(e.originalPolicy, "img-src \'none\'"); + assert_equals(e.disposition, "enforce"); + assert_equals(new URL(e.sourceFile).pathname, "/content-security-policy/support/inject-image.sub.js"); + assert_equals(e.lineNumber, 2); + assert_equals(e.columnNumber, 0); + assert_equals(e.statusCode, 200); + })); + + var s = document.createElement("script"); + s.src = "/content-security-policy/support/inject-image.sub.js"; + document.body.appendChild(s); + }, "Non-redirected cross-origin URLs are not stripped."); +</script> diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html new file mode 100644 index 0000000000..541c139533 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/content-security-policy/support/testharness-helper.js"></script> +<meta http-equiv="Content-Security-Policy" content="img-src 'none'"> +<body> +<script> + async_test(t => { + waitUntilEvent(window, "securitypolicyviolation") + .then(t.step_func_done(e => { + assert_equals(e.documentURI, document.location.toString()); + assert_equals(e.referrer, document.referrer); + assert_equals(e.blockedURI, "{{location[scheme]}}://{{location[host]}}/content-security-policy/support/fail.png"); + assert_equals(e.violatedDirective, "img-src"); + assert_equals(e.effectiveDirective, "img-src"); + assert_equals(e.originalPolicy, "img-src \'none\'"); + assert_equals(e.disposition, "enforce"); + assert_equals(new URL(e.sourceFile).pathname, "/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html"); + assert_equals(e.lineNumber, 25); + assert_equals(e.columnNumber, 4); + assert_equals(e.statusCode, 200); + })); + + var i = document.createElement("img"); + i.src = "/content-security-policy/support/fail.png"; + }, "Non-redirected same-origin URLs are not stripped."); +</script> + diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/source-file-blob-scheme.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/source-file-blob-scheme.html new file mode 100644 index 0000000000..ad3d9f3600 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/source-file-blob-scheme.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<meta http-equiv="Content-Security-Policy" content="script-src 'nonce-abc' blob:"> +<script nonce="abc" src="/resources/testharness.js"></script> +<script nonce="abc" src="/resources/testharnessreport.js"></script> +<script nonce="abc"> + async_test(t => { + var watcher = new EventWatcher(t, document, 'securitypolicyviolation'); + watcher.wait_for('securitypolicyviolation').then(t.step_func_done(e => { + assert_equals(e.blockedURI, "eval"); + assert_equals(e.sourceFile, "blob"); + assert_equals(e.lineNumber, 3); + assert_equals(e.columnNumber, 16); + })); + + var scriptText = ` + try { + eval("assert_unreached('no eval')"); + } catch (e) { + assert_equals(e.name, 'EvalError'); + } + `; + var s = document.createElement("script"); + s.src = URL.createObjectURL(new Blob([scriptText], {type: "text/javascript"})); + document.head.append(s); + }, "Violations from data:-URL scripts have a sourceFile of 'blob'"); +</script> diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/source-file-data-scheme.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/source-file-data-scheme.html new file mode 100644 index 0000000000..06511571d4 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/source-file-data-scheme.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<meta http-equiv="Content-Security-Policy" content="script-src 'nonce-abc' data:"> +<script nonce="abc" src="/resources/testharness.js"></script> +<script nonce="abc" src="/resources/testharnessreport.js"></script> +<script nonce="abc"> + async_test(t => { + var watcher = new EventWatcher(t, document, 'securitypolicyviolation'); + watcher.wait_for('securitypolicyviolation').then(t.step_func_done(e => { + assert_equals(e.blockedURI, "eval"); + assert_equals(e.sourceFile, "data"); + assert_equals(e.lineNumber, 3); + assert_equals(e.columnNumber, 16); + })); + + var scriptText = ` + try { + eval("assert_unreached('no eval')"); + } catch (e) { + assert_equals(e.name, 'EvalError'); + } + `; + var s = document.createElement("script"); + s.src = "data:text/javascript," + encodeURIComponent(scriptText); + document.head.append(s); + }, "Violations from data:-URL scripts have a sourceFile of 'data'"); +</script> diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/source-file.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/source-file.html new file mode 100644 index 0000000000..354b8dfd20 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/source-file.html @@ -0,0 +1,102 @@ +<meta http-equiv="Content-Security-Policy" content="require-trusted-types-for 'script';" /> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + +const policy = trustedTypes.createPolicy("sample", {createScript: x => x}); + +// Check CSP violated by a script originating from |input| returns a CSP +// violation whose sourceFile is |output|. +const testSourceFile = (description, input, output) => { + promise_test(async test => { + // Listen for TrustedType violation. + const violation = new Promise(resolve => { + document.addEventListener("securitypolicyviolation", e => { + resolve(e); + }, {once: true}); + }); + + // A trusted script using a customized sourceURL. The script's execution + // itself will trigger a TrustedType violation. + const trusted_script = policy.createScript(` + eval(''); + //# sourceURL=${input} + `) + try { + eval(trusted_script); + assert_unreached(); + } catch (e) {} + + assert_equals((await violation).sourceFile, output); + }, description); +}; + +testSourceFile("Basic HTTPS URL", + "http://dummy.test/script1.js", + "http://dummy.test/script1.js"); + +testSourceFile("Basic HTTP URL", + "https://dummy.test/script1.js", + "https://dummy.test/script1.js"); + +testSourceFile("Basic WSS URL", + "wss://dummy.test/script1.js", + "wss://dummy.test/script1.js"); + +testSourceFile("Basic WS URL", + "ws://dummy.test/script1.js", + "ws://dummy.test/script1.js"); + +testSourceFile("Fragment", + "https://dummy.test/script1.js#frag", + "https://dummy.test/script1.js"); + +testSourceFile("Query", + "https://dummy.test/script1.js?query", + "https://dummy.test/script1.js"); + +testSourceFile("Port", + "https://dummy.test:8080/script1.js", + "https://dummy.test:8080/script1.js"); + +testSourceFile("User:password", + "https://user:password@dummy.test/script1.js", + "https://dummy.test/script1.js"); + +testSourceFile("User", + "https://user@dummy.test/script1.js", + "https://dummy.test/script1.js"); + +testSourceFile("Invalid URL", + "script2.js", + ""); + +testSourceFile("file:", + "file:///temp/script3.js", + "file"); + +testSourceFile("Custom protocol", + "webpack://node_modules/sample/script4.js", + "webpack"); + +testSourceFile("about:blank", + "about:blank", + "about"); + +testSourceFile("about:custom", + "about:custom", + "about"); + +testSourceFile("data:", + "data:text/html;charset=utf8,<html></html>", + "data"); + +testSourceFile("blob:", + "blob:http://test.test/012345-6789-abcd-efab-0123456789", + "blob"); + +testSourceFile("javascript:", + "javascript:void(0)", + "javascript"); + +</script> diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/style-sample-no-opt-in.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/style-sample-no-opt-in.html new file mode 100644 index 0000000000..1fb0bf0c09 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/style-sample-no-opt-in.html @@ -0,0 +1,39 @@ +<!doctype html> +<meta http-equiv="Content-Security-Policy" content="style-src 'nonce-abc'"> +<script nonce="abc" src="/resources/testharness.js"></script> +<script nonce="abc" src="/resources/testharnessreport.js"></script> +<body> +<script nonce="abc"> + function waitForViolation(el) { + return new Promise(resolve => { + el.addEventListener('securitypolicyviolation', e => resolve(e)); + }); + } + + async_test(t => { + var s = document.createElement('style'); + s.innerText = "p { omg: yay !important; }"; + + waitForViolation(s) + .then(t.step_func_done(e => { + assert_equals(e.blockedURI, "inline"); + assert_equals(e.sample, ""); + })); + + document.head.append(s); + }, "Inline style blocks should not have a sample."); + + async_test(t => { + var p = document.createElement('p'); + p.setAttribute("style", "omg: yay !important;"); + p.innerText = "Yay!"; + + waitForViolation(p) + .then(t.step_func_done(e => { + assert_equals(e.blockedURI, "inline"); + assert_equals(e.sample, ""); + })); + + document.head.append(p); + }, "Inline style attributes should not have a sample."); +</script> diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/style-sample.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/style-sample.html new file mode 100644 index 0000000000..7eed52aac7 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/style-sample.html @@ -0,0 +1,39 @@ +<!doctype html> +<meta http-equiv="Content-Security-Policy" content="style-src 'nonce-abc' 'report-sample'"> +<script nonce="abc" src="/resources/testharness.js"></script> +<script nonce="abc" src="/resources/testharnessreport.js"></script> +<body> +<script nonce="abc"> + function waitForViolation(el) { + return new Promise(resolve => { + el.addEventListener('securitypolicyviolation', e => resolve(e)); + }); + } + + async_test(t => { + var s = document.createElement('style'); + s.innerText = "p { omg: yay !important; }"; + + waitForViolation(s) + .then(t.step_func_done(e => { + assert_equals(e.blockedURI, "inline"); + assert_equals(e.sample, "p { omg: yay !important; }"); + })); + + document.head.append(s); + }, "Inline style blocks should have a sample."); + + async_test(t => { + var p = document.createElement('p'); + p.setAttribute("style", "omg: yay !important;"); + p.innerText = "Yay!"; + + waitForViolation(p) + .then(t.step_func_done(e => { + assert_equals(e.blockedURI, "inline"); + assert_equals(e.sample, "omg: yay !important;"); + })); + + document.head.append(p); + }, "Inline style attributes should have a sample."); +</script> diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/inside-worker.sub.js b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/inside-worker.sub.js new file mode 100644 index 0000000000..58bd02fd9e --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/inside-worker.sub.js @@ -0,0 +1,57 @@ +importScripts("{{location[scheme]}}://{{host}}:{{location[port]}}/resources/testharness.js"); +importScripts("{{location[scheme]}}://{{host}}:{{location[port]}}/content-security-policy/support/testharness-helper.js"); + +var cspEventFiredInDocument = false; +// ServiceWorker and Worker +self.addEventListener("message", e => { + if (e.data == "SecurityPolicyViolation from Document") + cspEventFiredInDocument = true; +}); +// SharedWorker +self.addEventListener("connect", c => { + c.ports[0].addEventListener("message", m => { + if (m.data == "SecurityPolicyViolation from Document") + cspEventFiredInDocument = true; + }); +}); + +async_test(t => { + var url = "{{location[scheme]}}://{{host}}:{{location[port]}}/content-security-policy/support/resource.py"; + assert_no_csp_event_for_url(t, url); + + fetch(url) + .catch(t.unreached_func("Fetch should succeed.")) + .then(t.step_func_done(r => { + assert_equals(r.status, 200); + assert_false(cspEventFiredInDocument); + })); +}, "No SecurityPolicyViolation event fired for successful load."); + +async_test(t => { + var url = "{{location[scheme]}}://{{domains[www2]}}:{{location[port]}}/content-security-policy/support/resource.py"; + waitUntilCSPEventForURL(t, url) + .then(t.step_func_done(e => { + assert_equals(e.blockedURI, url); + assert_false(cspEventFiredInDocument); + })); + + fetch(url) + .then(t.unreached_func("Fetch should not succeed.")) + .catch(t.step_func(e => assert_true(e instanceof TypeError))); +}, "SecurityPolicyViolation event fired on global."); + +async_test(t => { + var url = "{{location[scheme]}}://{{host}}:{{location[port]}}/common/redirect.py?location={{location[scheme]}}://{{domains[www]}}:{{location[port]}}/content-security-policy/support/ping.js"; + waitUntilCSPEventForURL(t, url) + .then(t.step_func_done(e => { + assert_equals(e.blockedURI, url); + assert_false(cspEventFiredInDocument); + })); + + fetch(url) + .then(t.unreached_func("Fetch should not succeed.")) + .catch(t.step_func(e => assert_true(e instanceof TypeError))); +}, "SecurityPolicyViolation event fired on global with the correct blockedURI."); + +// Worker tests need an explicit `done()`. +done(); diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/inside-worker.sub.js.headers b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/inside-worker.sub.js.headers new file mode 100644 index 0000000000..50ff4a5b94 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/inside-worker.sub.js.headers @@ -0,0 +1,5 @@ +Expires: Mon, 26 Jul 1997 05:00:00 GMT +Cache-Control: no-store, no-cache, must-revalidate +Cache-Control: post-check=0, pre-check=0, false +Pragma: no-cache +Content-Security-Policy: connect-src 'self' diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/testharness-helper.sub.js b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/testharness-helper.sub.js new file mode 100644 index 0000000000..816b88fc6e --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/testharness-helper.sub.js @@ -0,0 +1,5 @@ +function generateCrossOriginRedirectImage() { + var target = "http://{{host}}:{{ports[https][0]}}/content-security-policy/support/pass.png"; + var url = "/common/redirect.py?location=" + encodeURIComponent(target); + return { url: url, target: target } +}
\ No newline at end of file diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/targeting.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/targeting.html new file mode 100644 index 0000000000..b21273ca55 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/targeting.html @@ -0,0 +1,169 @@ +<!doctype html> +<meta http-equiv="Content-Security-Policy" content="script-src 'nonce-abc'; style-src 'self'"> +<script nonce="abc" src="/resources/testharness.js"></script> +<script nonce="abc" src="/resources/testharnessreport.js"></script> +<script nonce="abc"> + var unexecuted_test = async_test("These tests should not fail."); + + async_test(t => { + var watcher = new EventWatcher(t, document, ['securitypolicyviolation']) + watcher.wait_for('securitypolicyviolation') + .then(t.step_func(e => { + assert_equals(e.blockedURI, "inline"); + assert_equals(e.target, document.querySelector('#block1')); + return watcher.wait_for('securitypolicyviolation'); + })) + .then(t.step_func(e => { + assert_equals(e.blockedURI, "inline"); + assert_equals(e.target, document.querySelector('#block2')); + return watcher.wait_for('securitypolicyviolation'); + })) + .then(t.step_func(e => { + assert_equals(e.blockedURI, "inline"); + assert_equals(e.target, document.querySelector('#block3')); + return watcher.wait_for('securitypolicyviolation'); + })) + .then(t.step_func(e => { + assert_equals(e.blockedURI, "inline"); + assert_equals(e.target, document.querySelector('#block4')); + return watcher.wait_for('securitypolicyviolation'); + })) + .then(t.step_func(e => { + assert_equals(e.blockedURI, "inline"); + assert_equals(e.target, document.querySelector('#block5')); + return watcher.wait_for('securitypolicyviolation'); + })) + .then(t.step_func(e => { + assert_equals(e.blockedURI, "inline"); + assert_equals(e.lineNumber, 118); + assert_in_array(e.columnNumber, [4, 6]); + assert_equals(e.target, document, "Elements created in this document, but pushed into a same-origin frame trigger on that frame's document, not on this frame's document."); + return watcher.wait_for('securitypolicyviolation'); + })) + .then(t.step_func(e => { + assert_equals(e.blockedURI, "inline"); + assert_equals(e.lineNumber, 131); + assert_in_array(e.columnNumber, [4, 59]); + assert_equals(e.target, document, "Elements created in this document, but pushed into a same-origin frame trigger on that frame's document, not on this frame's document."); + return watcher.wait_for('securitypolicyviolation'); + })) + .then(t.step_func(e => { + assert_equals(e.blockedURI, "inline"); + assert_equals(e.lineNumber, 139); + assert_in_array(e.columnNumber, [4, 6]); + assert_equals(e.target, document, "Inline event handlers for disconnected elements target the document."); + return watcher.wait_for('securitypolicyviolation'); + })) + .then(t.step_func(e => { + assert_equals(e.blockedURI, "inline"); + assert_equals(e.lineNumber, 0); + assert_equals(e.columnNumber, 0); + assert_equals(e.target, document, "Inline event handlers for elements disconnected after triggering target the document."); + })) + .then(t.step_func_done(_ => { + unexecuted_test.done(); + })); + }, "Inline violations target the right element."); + +</script> +<!-- Inline block with no nonce. --> +<script id="block1"> + unexecuted_test.assert_unreached("This code block should not execute."); +</script> + +<!-- Inline event handler. --> +<a id="block2" onclick="void(0)">Click me!</a> +<script nonce='abc'>document.querySelector('#block2').click();</script> + +<!-- Style block. --> +<style id="block3"> + p { color: red !important; } +</style> + +<!-- Inline event handler inside Shadow DOM --> +<div id="block4"></div> +<script nonce='abc'> + async_test(t => { + var shadow = document.querySelector('#block4').attachShadow({"mode":"closed"}); + shadow.innerHTML = "<a id='block4a' onclick='void(0)'>Click!</a>"; + var a = shadow.querySelector('#block4a'); + a.addEventListener('securitypolicyviolation', t.step_func_done(e => { + assert_equals(e.blockedURI, "inline"); + assert_equals(e.target, a); + })); + a.click(); + }, "Correct targeting inside shadow tree (inline handler)."); +</script> + +<!-- Inline event handler inside Shadow DOM --> +<div id="block5"></div> +<script nonce='abc'> + async_test(t => { + var shadow = document.querySelector('#block5').attachShadow({"mode":"closed"}); + var style = document.createElement('style'); + style.innerText = 'p { color: red; }'; + style.addEventListener('securitypolicyviolation', t.step_func_done(e => { + assert_equals(e.blockedURI, "inline"); + assert_equals(e.target, style); + })); + shadow.appendChild(style); + }, "Correct targeting inside shadow tree (style)."); +</script> + +<!-- Pushed into a same-origin Document that isn't this Document --> +<iframe id="block6"></iframe> +<script nonce="abc"> + async_test(t => { + var d = document.createElement("div"); + d.setAttribute("onclick", "void(0);"); + var events = 0; + d.addEventListener('securitypolicyviolation', t.step_func(e => { + events++; + assert_equals(e.blockedURI, "inline"); + assert_equals(e.target, d); + })); + document.querySelector('#block6').contentDocument.addEventListener('securitypolicyviolation', t.step_func_done(e => { + events++; + assert_equals(e.blockedURI, "inline"); + assert_equals(e.target, d); + assert_equals(events, 2); + })); + document.querySelector('#block6').contentDocument.body.appendChild(d); + }, "Elements created in this document, but pushed into a same-origin frame trigger on that frame's document, not on this frame's document."); +</script> + +<!-- Disconnected inline event handler --> +<script nonce="abc"> + async_test(t => { + var d = document.createElement("div"); + d.setAttribute("onclick", "void(0);"); + d.addEventListener('securitypolicyviolation', t.unreached_func()); + d.click(); + t.done(); + }, "Inline event handlers for disconnected elements target the document."); +</script> + +<!-- Inline event handler, disconnected after click. --> +<a id="block8" onclick="void(0)">Click me also!</a> +<script nonce="abc"> + async_test(t => { + var a = document.querySelector('#block8'); + a.addEventListener('securitypolicyviolation', t.unreached_func()); + a.click(); + a.parentNode.removeChild(a); + t.done(); + }, "Inline event handlers for elements disconnected after triggering target the document."); +</script> + +<!-- Disconnected in a DocumentFragment --> +<script nonce="abc"> + async_test(t => { + var f = new DocumentFragment(); + var d = document.createElement('div'); + d.setAttribute('onclick', 'void(0)'); + d.addEventListener('securitypolicyviolation', t.unreached_func()); + f.appendChild(d); + d.click(); + t.done(); + }, "Inline event handlers for elements in a DocumentFragment target the document."); +</script> diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html new file mode 100644 index 0000000000..a6617a9590 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html @@ -0,0 +1,100 @@ +<!doctype html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/security-features/resources/common.sub.js"></script> +<body></body> +<script> + function waitForViolation(el, effective_directive) { + return new Promise(resolve => { + el.addEventListener('securitypolicyviolation', e => { + if (e.effectiveDirective == effective_directive) + resolve(e); + }); + }); + } + + async_test(t => { + var url = getRequestURLs("img-tag", + "same-http-downgrade", + "no-redirect").testUrl; + var i = document.createElement('img'); + var loaded = false; + var reported = false; + waitForViolation(window, "img-src") + .then(t.step_func(e => { + reported = true; + if (loaded) + t.done(); + })); + i.onload = t.step_func(_ => { + loaded = true; + if (reported) + t.done(); + }); + i.onerror = t.unreached_func(url + " should load successfully."); + i.src = url; + document.body.appendChild(i); + }, "Upgraded image is reported"); + + async_test(t => { + var url = getRequestURLs("iframe-tag", + "same-http-downgrade", + "no-redirect").testUrl; + var i = document.createElement('iframe'); + var loaded = false; + var reported = false; + waitForViolation(window, "frame-src") + .then(t.step_func(e => { + reported = true; + if (loaded) + t.done(); + })); + window.addEventListener("message", t.step_func(e => { + if (e.source == i.contentWindow) { + i.remove(); + loaded = true; + if (reported) + t.done(); + } + })); + i.src = url; + document.body.appendChild(i); + }, "Upgraded iframe is reported"); + + async_test(t => { + // Load an HTTPS iframe, then navigate it to an HTTP URL and check that the HTTP URL is both upgraded and reported. + var url = getRequestURLs("iframe-tag", + "same-https", + "no-redirect").testUrl; + var navigate_to = getRequestURLs("iframe-tag", + "cross-http-downgrade", + "no-redirect").testUrl; + var upgraded = new URL(navigate_to); + upgraded.protocol = "https"; + + var i = document.createElement('iframe'); + var loaded = false; + var reported = false; + + window.addEventListener("message", t.step_func(e => { + if (e.source == i.contentWindow) { + if (e.data.location == url) { + waitForViolation(window, "frame-src") + .then(t.step_func(e => { + reported = true; + if (loaded) + t.done(); + })); + i.contentWindow.location.href = navigate_to; + } else if (e.data.location == upgraded) { + loaded = true; + if (reported) + t.done(); + } + } + })); + i.src = url; + document.body.appendChild(i); + }, "Navigated iframe is upgraded and reported"); +</script> +</html> diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html.headers b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html.headers new file mode 100644 index 0000000000..b8bec0b95e --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html.headers @@ -0,0 +1,2 @@ +Content-Security-Policy-Report-Only: frame-src https:; img-src https: +Content-Security-Policy: upgrade-insecure-requests |