Skip to content

Commit ba8060c

Browse files
Yoav Weisslutien
Yoav Weiss
authored andcommitted
Bug 1964703 [wpt PR 52360] - Integrity-Policy for script destinations,
Automatic update from web-platform-tests Integrity-Policy for script destinations This adds support for Integrity-Policy instead of `require-sri-for`, based on [1]. [1] w3c/webappsec-subresource-integrity#133 I2S: https://groups.google.com/a/chromium.org/g/blink-dev/c/Q304_OkDAZA/m/b3Bnyab9DgAJ Change-Id: I9599280eb94045951351368d2531d25c32c15681 Bug: 412588111 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6408111 Reviewed-by: Camille Lamy <[email protected]> Commit-Queue: Yoav Weiss (@Shopify) <[email protected]> Reviewed-by: Antonio Sartori <[email protected]> Reviewed-by: Adam Rice <[email protected]> Cr-Commit-Position: refs/heads/main@{#1456383} -- wpt-commits: 58c8754f2d64eda3c04c7afecca2be6799484f5b wpt-pr: 52360 Differential Revision: https://phabricator.services.mozilla.com/D249270
1 parent 9b06490 commit ba8060c

File tree

2 files changed

+268
-0
lines changed

2 files changed

+268
-0
lines changed
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<!doctype html>
2+
<head>
3+
<meta name="timeout" content="long">
4+
<script src="/resources/testharness.js"></script>
5+
<script src="/resources/testharnessreport.js"></script>
6+
<script src="/common/dispatcher/dispatcher.js"></script>
7+
<script src="/common/utils.js"></script>
8+
</head>
9+
<body>
10+
<script>
11+
const run_test = (test_case) => {
12+
promise_test(async () => {
13+
const REMOTE_EXECUTOR =
14+
`/common/dispatcher/remote-executor.html?pipe=`;
15+
const iframe_uuid = token();
16+
17+
const header_name = "Integrity-Policy";
18+
const header = `header(${header_name},${test_case.header_value})`;
19+
const iframe_url =
20+
`${REMOTE_EXECUTOR}${encodeURIComponent(header)}&uuid=${iframe_uuid}`;
21+
22+
const iframe = document.createElement('iframe');
23+
iframe.src = iframe_url;
24+
document.body.appendChild(iframe);
25+
26+
// Execute code directly from the iframe.
27+
const ctx = new RemoteContext(iframe_uuid);
28+
const result = await ctx.execute_script(async (test_case) => {
29+
const resource_url = "/content-security-policy/resources/ran.js";
30+
let report_observed_promise;
31+
32+
// Load a script with no integrity. If there's a policy in place, it
33+
// would be blocked.
34+
const loaded = await new Promise(resolve => {
35+
const script = document.createElement('script');
36+
script.onload = () => { resolve(true); };
37+
script.onerror = () => { resolve(false); };
38+
script.src = resource_url;
39+
document.body.appendChild(script);
40+
});
41+
return { blocked: !loaded, ran: window.ran };
42+
}, [test_case]);
43+
44+
assert_equals(!result.blocked, !!result.ran);
45+
assert_equals(result.blocked, test_case.expected.blocked);
46+
}, test_case.description);
47+
};
48+
49+
const test_cases = [
50+
{
51+
description: "Ensure that test is working with a valid destination",
52+
header_value: "blocked-destinations=\\(script\\)",
53+
expected: {blocked: true},
54+
},
55+
{
56+
description: "Ensure that test is working with a valid destination and source",
57+
header_value: "blocked-destinations=\\(script\\)\\, sources=\\(inline\\)",
58+
expected: {blocked: true},
59+
},
60+
{
61+
description: "Ensure that an empty header does not block",
62+
header_value: "",
63+
expected: {blocked: false},
64+
},
65+
{
66+
description: "Ensure that a destination header with a token value does not parse",
67+
header_value: "blocked-destinations=script",
68+
expected: {blocked: false},
69+
},
70+
{
71+
description: "Ensure that a destination header with an inner list of strings does not parse",
72+
header_value: 'blocked-destinations=\\("script"\\)',
73+
expected: {blocked: false},
74+
},
75+
{
76+
description: "Ensure that a destination header with an inner list of single-quote strings does not parse",
77+
header_value: "blocked-destinations=\\('script'\\)",
78+
expected: {blocked: false},
79+
},
80+
{
81+
description: "Ensure that a destination header with an unclosed inner list does not parse",
82+
header_value: "blocked-destinations=\\(script",
83+
expected: {blocked: false},
84+
},
85+
{
86+
description: "Ensure that a destination header with a malformed inner list does not parse",
87+
header_value: "blocked-destinations=\\(script\\,style\\)",
88+
expected: {blocked: false},
89+
},
90+
{
91+
description: "Ensure that an unknown destination does not enforce a policy",
92+
header_value: "blocked-destinations=\\(style\\)",
93+
expected: {blocked: false},
94+
},
95+
{
96+
description: "Ensure that an unknown source causes the policy to not be enforced",
97+
header_value: "blocked-destinations=\\(script\\)\\, sources=\\(telepathy\\)",
98+
expected: {blocked: false},
99+
},
100+
{
101+
description: "Ensure that an invalid source causes the policy to not be enforced",
102+
header_value: "blocked-destinations=\\(script\\)\\, sources=\\(invalid",
103+
expected: {blocked: false},
104+
},
105+
];
106+
test_cases.map(run_test);
107+
</script>
108+
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
<!doctype html>
2+
<script src="/resources/testharness.js"></script>
3+
<script src="/resources/testharnessreport.js"></script>
4+
<script src="/common/dispatcher/dispatcher.js"></script>
5+
<script src="/common/utils.js"></script>
6+
<script src="/common/get-host-info.sub.js"></script>
7+
8+
<body>
9+
<script>
10+
const {ORIGIN} = get_host_info();
11+
const getAbsoluteUrl = url => {
12+
return new URL(url, window.location.href).href;
13+
}
14+
15+
const run_test = (test_case) => {
16+
promise_test(async () => {
17+
const REMOTE_EXECUTOR =
18+
`/common/dispatcher/remote-executor.html?pipe=`;
19+
const iframe_uuid = token();
20+
21+
const header_name = test_case.report_only ?
22+
"Integrity-Policy-Report-Only" :
23+
"Integrity-Policy";
24+
25+
const header =
26+
`header(${header_name},blocked-destinations=\\(script\\)\\, endpoints=\\(integrity-endpoint\\))`;
27+
const iframe_url = `${REMOTE_EXECUTOR}${encodeURIComponent(header)}&uuid=${iframe_uuid}`;
28+
29+
const iframe = document.createElement('iframe');
30+
iframe.src = iframe_url;
31+
document.body.appendChild(iframe);
32+
33+
// Execute code directly from the iframe.
34+
const ctx = new RemoteContext(iframe_uuid);
35+
const result = await ctx.execute_script(async (test_case) => {
36+
// Load the script
37+
await new Promise(resolve => {
38+
const script = document.createElement('script');
39+
if (test_case.cross_origin) {
40+
script.crossOrigin="anonymous";
41+
}
42+
if (test_case.integrity) {
43+
script.integrity = test_case.integrity;
44+
}
45+
script.onload = () => { resolve(test_case.url); };
46+
script.onerror = () => { resolve(test_case.url); };
47+
script.src = test_case.url;
48+
document.body.appendChild(script);
49+
});
50+
return { ran: window.ran };
51+
}, [test_case]);
52+
assert_equals(!!result.ran, test_case.expected.ran);
53+
}, test_case.description);
54+
};
55+
56+
const blob = new Blob([`window.ran=true;`],
57+
{ type: 'application/javascript' });
58+
59+
const blob_url = URL.createObjectURL(blob);
60+
61+
// Generated using https://sha2.it/ed25519.html (In Chrome Canary, with Experimental Web Platform Features enabled)
62+
const signature = encodeURIComponent(
63+
'header(Unencoded-Digest, sha-384=:tqyFpeo21WFM8HDeUtLqH20GUq\/q3D1R6mqTzW3RtyTZ3dAYZJhC1wUcnkgOE2ak:)' +
64+
'|header(Signature-Input, signature=\\("unencoded-digest";sf\\); keyid="JrQLj5P\/89iXES9+vFgrIy29clF9CC\/oPPsw3c5D0bs="; tag="sri")' +
65+
'|header(Signature, signature=:qM19uLskHm2TQG5LJcH/hY0n0BWWzYOJztVWYlwk0cZb3u0JdgUMre1J4Jn8Tma0x2u5/kPBfbXRMbB+X+vTBw==:)');
66+
67+
const test_cases = [
68+
{
69+
description: "Ensure that a script without integrity did not run",
70+
url: "/content-security-policy/resources/ran.js",
71+
cross_origin: true,
72+
integrity: "",
73+
should_block: true,
74+
report_only: false,
75+
expected: {blocked: ORIGIN + "/content-security-policy/resources/ran.js", ran: false },
76+
},
77+
{
78+
description: "Ensure that a script with unknown integrity algorithm did not run",
79+
url: "/content-security-policy/resources/ran.js",
80+
cross_origin: true,
81+
integrity: "foobar-AAAAAAAAAAAAAAAAAAAa",
82+
should_block: true,
83+
report_only: false,
84+
expected: {blocked: ORIGIN + "/content-security-policy/resources/ran.js", ran: false },
85+
},
86+
{
87+
description: "Ensure that a script without integrity algorithm runs and gets reported in report-only mode",
88+
url: "/content-security-policy/resources/ran.js",
89+
cross_origin: true,
90+
integrity: "",
91+
should_block: true,
92+
report_only: true,
93+
expected: {blocked: ORIGIN + "/content-security-policy/resources/ran.js", ran: true },
94+
},
95+
{
96+
description: "Ensure that a no-cors script gets blocked",
97+
url: "/content-security-policy/resources/ran.js",
98+
cross_origin: false,
99+
integrity: "sha384-tqyFpeo21WFM8HDeUtLqH20GUq/q3D1R6mqTzW3RtyTZ3dAYZJhC1wUcnkgOE2ak",
100+
should_block: true,
101+
report_only: false,
102+
expected: {blocked: ORIGIN + "/content-security-policy/resources/ran.js", ran: false },
103+
},
104+
{
105+
description: "Ensure that a script with integrity runs",
106+
url: "/content-security-policy/resources/ran.js",
107+
cross_origin: true,
108+
integrity: "sha384-tqyFpeo21WFM8HDeUtLqH20GUq/q3D1R6mqTzW3RtyTZ3dAYZJhC1wUcnkgOE2ak",
109+
should_block: false,
110+
report_only: false,
111+
expected: {blocked: "", ran: true },
112+
},
113+
{
114+
description: "Ensure that a script with signature integrity runs",
115+
url: "/content-security-policy/resources/ran.js?pipe=" + signature,
116+
cross_origin: true,
117+
integrity: "ed25519-JrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs=",
118+
should_block: false,
119+
report_only: false,
120+
expected: {blocked: "", ran: true },
121+
},
122+
{
123+
description: "Ensure that a data URI script with no integrity runs",
124+
url: "data:application/javascript,window.ran=true",
125+
cross_origin: true,
126+
integrity: "",
127+
should_block: false,
128+
report_only: false,
129+
expected: {blocked: "", ran: true },
130+
},
131+
{
132+
description: "Ensure that a no-CORS data URI script with no integrity runs",
133+
url: "data:application/javascript,window.ran=true",
134+
cross_origin: false,
135+
integrity: "",
136+
should_block: false,
137+
report_only: false,
138+
expected: {blocked: "", ran: true },
139+
},
140+
{
141+
description: "Ensure that a blob URL script with no integrity runs",
142+
url: blob_url,
143+
cross_origin: true,
144+
integrity: "",
145+
should_block: false,
146+
report_only: false,
147+
expected: {blocked: "", ran: true },
148+
},
149+
{
150+
description: "Ensure that a no-CORS blob URL script with no integrity runs",
151+
url: blob_url,
152+
cross_origin: false,
153+
integrity: "",
154+
should_block: false,
155+
report_only: false,
156+
expected: {blocked: "", ran: true },
157+
}
158+
];
159+
test_cases.map(run_test);
160+
</script>

0 commit comments

Comments
 (0)