tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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>