script-url-allowed-by-hash.https.html (11040B)
1 <!DOCTYPE HTML> 2 <html> 3 4 <head> 5 <title>Scripts should be allowed if a matching URL hash is present</title> 6 <script src="/common/get-host-info.sub.js"></script> 7 <script src='/resources/testharness.js'></script> 8 <script src='/resources/testharnessreport.js'c'></script> 9 <script src='support/util.js' nonce='abc'></script> 10 </head> 11 12 <body> 13 <script> 14 const { ORIGIN, REMOTE_ORIGIN } = get_host_info(); 15 const scriptUrl = new URL("./support/externalScript.js", document.location).toString(); 16 const dynamicScriptUrl = new URL("./support/add_dynamic_script.js", document.location).toString(); 17 const redirectUrl = new URL("/common/redirect.py?location=" + scriptUrl, document.location).toString(); 18 19 // This is the hash of the string 'foo.js': 20 const wrongHash = "LJVNbdCJGjP5027dMuLOQeMEiDI8JvMr5zMiXqW5tzs="; 21 22 function get_iframe_url(test_type, policy, script_url) { 23 return test_type == "header" ? 24 `support/iframe.sub.html?pipe=header(Content-Security-Policy,${policy})&script_url=${script_url}`: 25 `support/iframe_meta.sub.html?policy=${policy}&script_url=${script_url}`; 26 } 27 28 function get_iframe_url_with_inline_script(test_type, policy) { 29 return test_type == "header" ? 30 `support/iframe_inline.sub.html?pipe=header(Content-Security-Policy,${policy})`: 31 `support/iframe_inline_meta.sub.html?policy=${policy}`; 32 } 33 34 function get_iframe_url_in_child_dir(test_type, policy, script_url) { 35 return test_type == "header" ? 36 `support/child_dir/iframe.sub.html?pipe=header(Content-Security-Policy,${policy})&script_url=${script_url}`: 37 `support/child_dir/iframe_meta.sub.html?policy=${policy}&script_url=${script_url}`; 38 } 39 40 for (let test_type of ["header", "metatag"]) { 41 42 promise_test(async t => { 43 const scriptUrlHash = await sha256ofURL(scriptUrl); 44 const policy = `script-src 'nonce-forinlinescript' 'url-sha256-${scriptUrlHash}'` 45 46 let frame = document.createElement('iframe'); 47 frame.src = get_iframe_url(test_type, policy, 'externalScript.js'); 48 document.body.appendChild(frame); 49 50 const msgEvent = await new Promise(resolve => window.onmessage = resolve); 51 assert_equals(msgEvent.data, 'SCRIPT_RAN'); 52 }, "script-src should allow script by its url hash - " + test_type); 53 54 promise_test(async t => { 55 const policy = `script-src 'nonce-forinlinescript' 'url-sha256-${wrongHash}' ${ORIGIN} ${REMOTE_ORIGIN}` 56 57 let frame = document.createElement('iframe'); 58 frame.src = get_iframe_url(test_type, policy, 'externalScript.js'); 59 document.body.appendChild(frame); 60 61 const msgEvent = await new Promise(resolve => window.onmessage = resolve); 62 assert_equals(msgEvent.data, 'CSP_VIOLATION'); 63 }, "A parseable url-hash should ignore hostname allowlists - " + test_type); 64 65 // TODO(crbug.com/414459670): Add a test with an invalid url-hash. 66 67 promise_test(async t => { 68 const scriptUrlHash = await sha256ofURL(scriptUrl); 69 const policy = `default-src 'nonce-forinlinescript' 'url-sha256-${scriptUrlHash}'` 70 71 let frame = document.createElement('iframe'); 72 frame.src = get_iframe_url(test_type, policy, 'externalScript.js'); 73 document.body.appendChild(frame); 74 75 const msgEvent = await new Promise(resolve => window.onmessage = resolve); 76 assert_equals(msgEvent.data, 'SCRIPT_RAN'); 77 }, "default-src should allow script by its url hash - " + test_type); 78 79 promise_test(async t => { 80 const scriptUrlHash = await sha256ofURL(scriptUrl); 81 const policy = `script-src-elem 'nonce-forinlinescript' 'url-sha256-${scriptUrlHash}'` 82 83 let frame = document.createElement('iframe'); 84 frame.src = get_iframe_url(test_type, policy, 'externalScript.js'); 85 document.body.appendChild(frame); 86 87 const msgEvent = await new Promise(resolve => window.onmessage = resolve); 88 assert_equals(msgEvent.data, 'SCRIPT_RAN'); 89 }, "script-src-elem should allow script by its url hash - " + test_type); 90 91 promise_test(async t => { 92 // externalScript.js isn't allowlisted: 93 const dynamicScriptUrlHash = await sha256ofURL(dynamicScriptUrl); 94 const policy = `script-src 'nonce-forinlinescript' 'url-sha256-${dynamicScriptUrlHash}'` 95 96 let frame = document.createElement('iframe'); 97 frame.src = get_iframe_url(test_type, policy, 'add_dynamic_script.js'); 98 document.body.appendChild(frame); 99 100 const msgEvent = await new Promise(resolve => window.onmessage = resolve); 101 assert_equals(msgEvent.data, 'CSP_VIOLATION'); 102 }, "url hashes should not allow dynamically inserted script transitively - " + test_type); 103 104 promise_test(async t => { 105 const scriptUrlHash = await sha256ofURL(scriptUrl); 106 const dynamicScriptUrlHash = await sha256ofURL(dynamicScriptUrl); 107 const policy = `script-src 'nonce-forinlinescript' 'url-sha256-${dynamicScriptUrlHash}' 'url-sha256-${scriptUrlHash}'` 108 109 let frame = document.createElement('iframe'); 110 frame.src = get_iframe_url(test_type, policy, 'add_dynamic_script.js'); 111 document.body.appendChild(frame); 112 113 const msgEvent = await new Promise(resolve => window.onmessage = resolve); 114 assert_equals(msgEvent.data, 'SCRIPT_RAN'); 115 }, "url hashes should allow dynamically inserted script if allowlisted - " + test_type); 116 117 promise_test(async t => { 118 // externalScript.js isn't explicitly allowlisted but it should be allowed: 119 const redirectUrlHash = await sha256ofURL(redirectUrl); 120 const policy = `script-src 'nonce-forinlinescript' 'url-sha256-${redirectUrlHash}'` 121 122 let frame = document.createElement('iframe'); 123 frame.src = get_iframe_url(test_type, policy, redirectUrl); 124 document.body.appendChild(frame); 125 126 const msgEvent = await new Promise(resolve => window.onmessage = resolve); 127 assert_equals(msgEvent.data, 'SCRIPT_RAN'); 128 }, "url hashes should allow redirected scripts - " + test_type); 129 130 // Tests for strict-dynamic-url keyword: 131 132 promise_test(async t => { 133 // add_dynamic_script.js isn't allowlisted but strict-dynamic-url should allow it: 134 const dynamicScriptUrlHash = await sha256ofURL(dynamicScriptUrl); 135 const policy = `script-src 'nonce-forinlinescript' 'strict-dynamic-url' 'url-sha256-${dynamicScriptUrlHash}'` 136 137 let frame = document.createElement('iframe'); 138 frame.src = get_iframe_url(test_type, policy, 'add_dynamic_script.js'); 139 document.body.appendChild(frame); 140 141 const msgEvent = await new Promise(resolve => window.onmessage = resolve); 142 assert_equals(msgEvent.data, 'SCRIPT_RAN'); 143 }, "dynamically inserted parser-inserted script should be allowed if strict-dynamic-url is present - " + test_type); 144 145 promise_test(async t => { 146 // externalScript.js isn't allowlisted but strict-dynamic-url should allow it: 147 const scriptUrlHash = await sha256ofURL(scriptUrl); 148 // This is the hash of the inline script that dynamically inserts externalScript.js. 149 const inlineScriptHash = "F8UqObF6TSi2W4dDcDzAOAplJkYovBE6JpJjsZJy5HA="; 150 const policy = `script-src 'nonce-forinlinescript' 'strict-dynamic-url' 'sha256-${inlineScriptHash}'` 151 152 let frame = document.createElement('iframe'); 153 frame.src = get_iframe_url_with_inline_script(test_type, policy); 154 document.body.appendChild(frame); 155 156 const msgEvent = await new Promise(resolve => window.onmessage = resolve); 157 assert_equals(msgEvent.data, 'SCRIPT_RAN'); 158 }, "dynamically inserted script inserted by an inline script should be allowed if strict-dynamic-url is present - " + test_type); 159 160 // Relative URL tests: 161 162 promise_test(async t => { 163 const scriptUrlHash = await sha256ofURL("externalScript.js"); 164 const policy = `script-src 'nonce-forinlinescript' 'url-sha256-${scriptUrlHash}'` 165 166 let frame = document.createElement('iframe'); 167 frame.src = get_iframe_url(test_type, policy, 'externalScript.js'); 168 document.body.appendChild(frame); 169 170 const msgEvent = await new Promise(resolve => window.onmessage = resolve); 171 assert_equals(msgEvent.data, 'SCRIPT_RAN'); 172 }, "script-src should allow script by its relative url's hash - " + test_type); 173 174 promise_test(async t => { 175 const scriptUrlHash = await sha256ofURL("child_dir/externalScript.js"); 176 const policy = `script-src 'nonce-forinlinescript' 'url-sha256-${scriptUrlHash}'` 177 178 let frame = document.createElement('iframe'); 179 frame.src = get_iframe_url(test_type, policy, 'child_dir/externalScript.js'); 180 document.body.appendChild(frame); 181 182 const msgEvent = await new Promise(resolve => window.onmessage = resolve); 183 assert_equals(msgEvent.data, 'SCRIPT_RAN'); 184 }, "script-src should allow script by its relative url's hash in child directory - " + test_type); 185 186 promise_test(async t => { 187 const scriptUrlHash = await sha256ofURL("./externalScript.js"); 188 const policy = `script-src 'nonce-forinlinescript' 'url-sha256-${scriptUrlHash}'` 189 190 let frame = document.createElement('iframe'); 191 frame.src = get_iframe_url(test_type, policy, 'externalScript.js'); 192 document.body.appendChild(frame); 193 194 const msgEvent = await new Promise(resolve => window.onmessage = resolve); 195 assert_equals(msgEvent.data, 'CSP_VIOLATION'); 196 }, "script-src should disallow script with incorrect relative url hash - " + test_type); 197 198 // Relative URL tests with iframes in support/child_dir. 199 200 promise_test(async t => { 201 const scriptUrlHash = await sha256ofURL("externalScript.js"); 202 const policy = `script-src 'nonce-forinlinescript' 'url-sha256-${scriptUrlHash}'` 203 204 let frame = document.createElement('iframe'); 205 frame.src = get_iframe_url_in_child_dir(test_type, policy, 'externalScript.js'); 206 document.body.appendChild(frame); 207 208 const msgEvent = await new Promise(resolve => window.onmessage = resolve); 209 assert_equals(msgEvent.data, 'SCRIPT_RAN'); 210 }, "script-src should allow script by its relative url's hash in an iframe in child dir - " + test_type); 211 212 promise_test(async t => { 213 const scriptUrlHash = await sha256ofURL("../externalScript.js"); 214 const policy = `script-src 'nonce-forinlinescript' 'url-sha256-${scriptUrlHash}'` 215 216 let frame = document.createElement('iframe'); 217 frame.src = get_iframe_url_in_child_dir(test_type, policy, '../externalScript.js'); 218 document.body.appendChild(frame); 219 220 const msgEvent = await new Promise(resolve => window.onmessage = resolve); 221 assert_equals(msgEvent.data, 'SCRIPT_RAN'); 222 }, "script-src should allow script in parent dir by its relative url's hash in an iframe in child dir - " + test_type); 223 224 } 225 226 </script> 227 </body> 228 229 </html>