script-nonces-hidden.html (5813B)
1 <!DOCTYPE html> 2 <script src="/resources/testharness.js" nonce="abc"></script> 3 <script src="/resources/testharnessreport.js" nonce="abc"></script> 4 5 <!-- `Content-Security-Policy: script-src 'nonce-abc'; img-src 'none'` delivered via headers --> 6 7 <body> 8 <!-- Basics --> 9 <script nonce="abc" id="testScript"> 10 document.currentScript.setAttribute('executed', 'yay'); 11 </script> 12 13 <script nonce="abc"> 14 var script = document.querySelector('#testScript'); 15 16 test(t => { 17 // Query Selector 18 assert_equals(document.querySelector('body [nonce]'), script); 19 assert_equals(document.querySelector('body [nonce=""]'), script); 20 assert_equals(document.querySelector('body [nonce=abc]'), null); 21 22 assert_equals(script.getAttribute('nonce'), ''); 23 assert_equals(script.nonce, 'abc'); 24 }, "Reading 'nonce' content attribute and IDL attribute."); 25 26 // Clone node. 27 test(t => { 28 script.setAttribute('executed', 'boo'); 29 var s2 = script.cloneNode(); 30 assert_equals(s2.nonce, 'abc', 'IDL attribute'); 31 assert_equals(s2.getAttribute('nonce'), ''); 32 }, "Cloned node retains nonce."); 33 34 async_test(t => { 35 var s2 = script.cloneNode(); 36 document.head.appendChild(s2); 37 assert_equals(s2.nonce, 'abc'); 38 assert_equals(s2.getAttribute('nonce'), ''); 39 40 window.addEventListener('load', t.step_func_done(_ => { 41 // The cloned script won't execute, as its 'already started' flag is set. 42 assert_equals(s2.getAttribute('executed'), 'boo'); 43 })); 44 }, "Cloned node retains nonce when inserted."); 45 46 // Set the content attribute to 'foo' 47 test(t => { 48 script.setAttribute('nonce', 'foo'); 49 assert_equals(script.getAttribute('nonce'), 'foo'); 50 assert_equals(script.nonce, 'foo'); 51 }, "Writing 'nonce' content attribute."); 52 53 // Set the IDL attribute to 'bar' 54 test(t => { 55 script.nonce = 'bar'; 56 assert_equals(script.nonce, 'bar'); 57 assert_equals(script.getAttribute('nonce'), 'foo'); 58 }, "Writing 'nonce' IDL attribute."); 59 60 // Fragment parser. 61 var documentWriteTest = async_test("Document-written script executes."); 62 document.write(`<script nonce='abc'> 63 documentWriteTest.done(); 64 test(t => { 65 var script = document.currentScript; 66 assert_equals(script.getAttribute('nonce'), ''); 67 assert_equals(script.nonce, 'abc'); 68 }, "Document-written script's nonce value."); 69 </scr` + `ipt>`); 70 71 // Create node. 72 async_test(t => { 73 var s = document.createElement('script'); 74 s.innerText = script.innerText; 75 s.nonce = 'abc'; 76 assert_equals(s.nonce, 'abc'); 77 assert_equals(s.getAttribute('nonce'), null); 78 document.head.appendChild(s); 79 assert_equals(s.nonce, 'abc'); 80 assert_equals(s.getAttribute('nonce'), null); 81 82 window.addEventListener('load', t.step_func_done(_ => { 83 assert_equals(s.getAttribute('executed'), 'yay'); 84 })); 85 }, "createElement.nonce."); 86 87 async_test(t => { 88 var s = document.createElement('script'); 89 s.innerText = script.innerText; 90 s.nonce = 'zyx'; 91 s.setAttribute('nonce', 'abc'); 92 assert_equals(s.nonce, 'abc'); 93 document.head.appendChild(s); 94 assert_equals(s.nonce, 'abc'); 95 assert_equals(s.getAttribute('nonce'), ''); 96 97 window.addEventListener('load', t.step_func_done(_ => { 98 assert_equals(s.getAttribute('executed'), 'yay'); 99 })); 100 }, "setAttribute('nonce') overwrites '.nonce' upon insertion."); 101 102 // Create node. 103 async_test(t => { 104 var s = document.createElement('script'); 105 s.innerText = script.innerText; 106 s.setAttribute('nonce', 'abc'); 107 assert_equals(s.getAttribute('nonce'), 'abc', "Pre-insertion content"); 108 assert_equals(s.nonce, 'abc', "Pre-insertion IDL"); 109 document.head.appendChild(s); 110 assert_equals(s.nonce, 'abc', "Post-insertion IDL"); 111 assert_equals(s.getAttribute('nonce'), '', "Post-insertion content"); 112 113 window.addEventListener('load', t.step_func_done(_ => { 114 assert_equals(s.getAttribute('executed'), 'yay'); 115 })); 116 }, "createElement.setAttribute."); 117 </script> 118 119 <!-- Custom Element --> 120 <script nonce="abc"> 121 var eventList = []; 122 class NonceElement extends HTMLElement { 123 static get observedAttributes() { 124 return ['nonce']; 125 } 126 127 constructor() { 128 super(); 129 } 130 131 attributeChangedCallback(name, oldValue, newValue) { 132 eventList.push({ 133 type: "AttributeChanged", 134 name: name, 135 oldValue: oldValue, 136 newValue: newValue 137 }); 138 } 139 140 connectedCallback() { 141 eventList.push({ 142 type: "Connected", 143 }); 144 } 145 } 146 147 customElements.define("nonce-element", NonceElement); 148 </script> 149 <nonce-element nonce="abc"></nonce-element> 150 <script nonce="abc"> 151 test(t => { 152 assert_object_equals(eventList[0], { type: "AttributeChanged", name: "nonce", oldValue: null, newValue: "abc" }, "AttributeChanged 1"); 153 assert_object_equals(eventList[1], { type: "Connected" }, "Connected"); 154 assert_object_equals(eventList[2], { type: "AttributeChanged", name: "nonce", oldValue: "abc", newValue: "" }, "AttributeChanged 2"); 155 assert_equals(eventList.length, 3); 156 }, "Custom elements expose the correct events."); 157 </script> 158 159 <!-- CSS Leakage --> 160 <style> 161 #cssTest { display: block; } 162 #cssTest[nonce=abc] { background: url(/security/resources/abe.png); } 163 </style> 164 <script nonce="abc" id="cssTest"> 165 test(t => { 166 const script = document.querySelector('#cssTest'); 167 t.add_cleanup(() => script.remove()); 168 var style = getComputedStyle(script); 169 assert_equals(style['display'], 'block'); 170 assert_equals(style['background-image'], 'none'); 171 }, "Nonces don't leak via CSS side-channels."); 172 </script>