Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

require-sri-for: 'script' #50681

Merged
merged 1 commit into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion common/dispatcher/remote-executor.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
<meta charset="utf-8">
<body>
</body>
<script src="./dispatcher.js"></script>
<script src="./dispatcher.js"
crossorigin
integrity="sha256-daCATx8B9i1s6ixqZvCGcGQOv3a+VMoor6aS9UNUoiY=">
</script>
<script>
const params = new URLSearchParams(window.location.search);
const uuid = params.get('uuid');
Expand Down
1 change: 1 addition & 0 deletions content-security-policy/resources/ran.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
window.ran = true;
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<meta http-equiv="Content-Security-Policy" content="require-sri-for 'script'">
<script>
window.executed_test = async_test("Script that requires integrity executes and does not generate a violation report.");
document.addEventListener('securitypolicyviolation', executed_test.unreached_func("No report should be generated."));
</script>
<script crossorigin integrity="sha384-tqyFpeo21WFM8HDeUtLqH20GUq/q3D1R6mqTzW3RtyTZ3dAYZJhC1wUcnkgOE2ak"
src="/content-security-policy/resources/ran.js"></script>
<script>
assert_true(window.ran);
window.executed_test.done();
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<meta http-equiv="Content-Security-Policy" content="require-sri-for 'script'">
<script src="/content-security-policy/resources/ran.js"></script>
<script>
promise_test(async t => {
const watcher = new EventWatcher(t, document, ['securitypolicyviolation']);
const e = await watcher.wait_for('securitypolicyviolation');
assert_equals(e.blockedURI, `${location.origin}/content-security-policy/resources/ran.js`);
assert_true(typeof(window.ran) == "undefined", "Script did not ran");
}, "Test that meta require-sri-for blocks scripts with no SRI");
</script>
148 changes: 148 additions & 0 deletions content-security-policy/tentative/require-sri-for/script.https.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/dispatcher/dispatcher.js"></script>
<script src="/common/utils.js"></script>
<script src="/common/get-host-info.sub.js"></script>

<body>
<script>
const {ORIGIN} = get_host_info();

const run_test = async (test_case) => {
promise_test(async () => {
const REMOTE_EXECUTOR =
`/common/dispatcher/remote-executor.html?pipe=`;
const iframe_uuid = token();

const csp_header = test_case.report_only ?
"header(Content-Security-Policy-Report-Only,require-sri-for 'script')" :
"header(Content-Security-Policy,require-sri-for 'script')";
const iframe_url = REMOTE_EXECUTOR + encodeURIComponent(csp_header);

const iframe = document.createElement('iframe');
iframe.src = iframe_url + `&uuid=${iframe_uuid}`;
document.body.appendChild(iframe);

// Execute code directly from the iframe.
const ctx = new RemoteContext(iframe_uuid);
const result = await ctx.execute_script(async (test_case) => {
let blockedURI;
if (test_case.should_block) {
window.addEventListener("securitypolicyviolation", e => {
blockedURI = e.blockedURI;
});
}

// Load the script
await new Promise(resolve => {
const script = document.createElement('script');
if (test_case.cross_origin) {
script.crossOrigin="anonymous";
}
if (test_case.integrity) {
script.integrity = test_case.integrity;
}
script.onload = resolve;
script.onerror = resolve;
script.src = test_case.url;
document.body.appendChild(script);
});

if (test_case.should_block && !window.ran) {
return blockedURI;
} else {
return window.ran;
}
}, [test_case]);
assert_equals(result, test_case.expected);
}, test_case.description);
};

const blob = new Blob([`window.ran=true;`],
{ type: 'application/javascript' });

const blob_url = URL.createObjectURL(blob);

// Generated using https://sha2.it/ed25519.html (In Chrome Canary, with Experimental Web Platform Features enabled)
const signature = encodeURIComponent(
'header(Unencoded-Digest, sha-384=:tqyFpeo21WFM8HDeUtLqH20GUq\/q3D1R6mqTzW3RtyTZ3dAYZJhC1wUcnkgOE2ak:)' +
'|header(Signature-Input, signature=\\("unencoded-digest";sf\\); keyid="JrQLj5P\/89iXES9+vFgrIy29clF9CC\/oPPsw3c5D0bs="; tag="sri")' +
'|header(Signature, signature=:qM19uLskHm2TQG5LJcH/hY0n0BWWzYOJztVWYlwk0cZb3u0JdgUMre1J4Jn8Tma0x2u5/kPBfbXRMbB+X+vTBw==:)');

const test_cases = [
{
description: "Ensure that a script without integrity did not run",
url: "/content-security-policy/resources/ran.js",
cross_origin: true,
integrity: "",
should_block: true,
expected: ORIGIN + "/content-security-policy/resources/ran.js",
report_only: false,
},
{
description: "Ensure that a script with unknown integrity algorithm did not run",
url: "/content-security-policy/resources/ran.js",
cross_origin: true,
integrity: "foobar-AAAAAAAAAAAAAAAAAAAa",
should_block: true,
expected: ORIGIN + "/content-security-policy/resources/ran.js",
report_only: false,
},
{
description: "Ensure that a script without integrity algorithm runs and gets reported in report-only mode",
url: "/content-security-policy/resources/ran.js",
cross_origin: true,
integrity: "",
should_block: true,
expected: true,
report_only: true,
},
{
description: "Ensure that a no-cors script gets blocked",
url: "/content-security-policy/resources/ran.js",
cross_origin: false,
integrity: "sha384-tqyFpeo21WFM8HDeUtLqH20GUq/q3D1R6mqTzW3RtyTZ3dAYZJhC1wUcnkgOE2ak",
should_block: true,
expected: ORIGIN + "/content-security-policy/resources/ran.js",
report_only: false,
},
{
description: "Ensure that a script with integrity runs",
url: "/content-security-policy/resources/ran.js",
cross_origin: true,
integrity: "sha384-tqyFpeo21WFM8HDeUtLqH20GUq/q3D1R6mqTzW3RtyTZ3dAYZJhC1wUcnkgOE2ak",
should_block: false,
expected: true,
report_only: false,
},
{
description: "Ensure that a script with signature integrity runs",
url: "/content-security-policy/resources/ran.js?pipe=" + signature,
cross_origin: true,
integrity: "ed25519-JrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs=",
should_block: false,
expected: true,
report_only: false,
},
{
description: "Ensure that a data URI script with no integrity runs",
url: "data:application/javascript,window.ran=true",
cross_origin: true,
integrity: "",
should_block: false,
expected: true,
report_only: false,
},
{
description: "Ensure that a blob URL script with no integrity runs",
url: blob_url,
cross_origin: true,
integrity: "",
should_block: false,
expected: true,
report_only: false,
}
];
test_cases.map(run_test);
</script>