test_iframe_sandbox.html (7840B)
1 <!DOCTYPE HTML> 2 <html> 3 <!-- 4 https://bugzilla.mozilla.org/show_bug.cgi?id=671389 5 Bug 671389 - Implement CSP sandbox directive 6 --> 7 <head> 8 <meta charset="utf-8"> 9 <title>Tests for Bug 671389</title> 10 <script src="/tests/SimpleTest/SimpleTest.js"></script> 11 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> 12 </head> 13 <script type="application/javascript"> 14 15 SimpleTest.waitForExplicitFinish(); 16 17 // Check if two sandbox flags are the same, ignoring case-sensitivity. 18 // getSandboxFlags returns a list of sandbox flags (if any) or 19 // null if the flag is not set. 20 // This function checks if two flags are the same, i.e., they're 21 // either not set or have the same flags. 22 function eqFlags(a, b) { 23 if (a === null && b === null) { return true; } 24 if (a === null || b === null) { return false; } 25 if (a.length !== b.length) { return false; } 26 var a_sorted = a.map(function(e) { return e.toLowerCase(); }).sort(); 27 var b_sorted = b.map(function(e) { return e.toLowerCase(); }).sort(); 28 for (var i in a_sorted) { 29 if (a_sorted[i] !== b_sorted[i]) { 30 return false; 31 } 32 } 33 return true; 34 } 35 36 // Get the sandbox flags of document doc. 37 // If the flag is not set sandboxFlagsAsString returns null, 38 // this function also returns null. 39 // If the flag is set it may have some flags; in this case 40 // this function returns the (potentially empty) list of flags. 41 function getSandboxFlags(doc) { 42 var flags = doc.sandboxFlagsAsString; 43 if (flags === null) { return null; } 44 return flags? flags.split(" "):[]; 45 } 46 47 // Constructor for a CSP sandbox flags test. The constructor 48 // expectes a description 'desc' and set of options 'opts': 49 // - sandboxAttribute: [null] or string corresponding to the iframe sandbox attributes 50 // - csp: [null] or string corresponding to the CSP sandbox flags 51 // - cspReportOnly: [null] or string corresponding to the CSP report-only sandbox flags 52 // - file: [null] or string corresponding to file the server should serve 53 // Above, we use [brackets] to denote default values. 54 function CSPFlagsTest(desc, opts) { 55 function ifundef(x, v) { 56 return (x !== undefined) ? x : v; 57 } 58 59 function intersect(as, bs) { // Intersect two csp attributes: 60 as = as === null ? null 61 : as.split(' ').filter(function(x) { return !!x; }); 62 bs = bs === null ? null 63 : bs.split(' ').filter(function(x) { return !!x; }); 64 65 if (as === null) { return bs; } 66 if (bs === null) { return as; } 67 68 var cs = []; 69 as.forEach(function(a) { 70 if (a && bs.includes(a)) 71 cs.push(a); 72 }); 73 return cs; 74 } 75 76 this.desc = desc || "Untitled test"; 77 this.attr = ifundef(opts.sandboxAttribute, null); 78 this.csp = ifundef(opts.csp, null); 79 this.cspRO = ifundef(opts.cspReportOnly, null); 80 this.file = ifundef(opts.file, null); 81 this.expected = intersect(this.attr, this.csp); 82 } 83 84 // Return function that checks that the actual flags are the same as the 85 // expected flags 86 CSPFlagsTest.prototype.checkFlags = function(iframe) { 87 var this_ = this; 88 return function() { 89 try { 90 var actual = getSandboxFlags(SpecialPowers.wrap(iframe).contentDocument); 91 ok(eqFlags(actual, this_.expected), 92 this_.desc + ' - expected: "' + this_.expected + '", got: "' + actual + '"'); 93 } catch (e) { 94 ok(false, 95 this_.desc + ' - expected: "' + this_.expected + '", failed with: "' + e + '"'); 96 } 97 runNextTest(); 98 }; 99 }; 100 101 // Set the iframe src and sandbox attribute 102 CSPFlagsTest.prototype.runTest = function () { 103 var iframe = document.createElement('iframe'); 104 document.getElementById("content").appendChild(iframe); 105 iframe.onload = this.checkFlags(iframe); 106 107 // set sandbox attribute 108 if (this.attr === null) { 109 iframe.removeAttribute('sandbox'); 110 } else { 111 iframe.sandbox = this.attr; 112 } 113 114 // set query string 115 var src = 'http://mochi.test:8888/tests/dom/security/test/csp/file_testserver.sjs'; 116 117 var delim = '?'; 118 119 if (this.csp !== null) { 120 src += delim + 'csp=' + escape('sandbox ' + this.csp); 121 delim = '&'; 122 } 123 124 if (this.cspRO !== null) { 125 src += delim + 'cspRO=' + escape('sandbox ' + this.cspRO); 126 delim = '&'; 127 } 128 129 if (this.file !== null) { 130 src += delim + 'file=' + escape(this.file); 131 delim = '&'; 132 } 133 134 iframe.src = src; 135 iframe.width = iframe.height = 10; 136 137 } 138 139 testCases = [ 140 { 141 desc: "Test 1: Header should not override attribute", 142 sandboxAttribute: "", 143 csp: "allow-forms aLLOw-POinter-lock alLOW-popups aLLOW-SAME-ORIGin ALLOW-SCRIPTS allow-top-navigation" 144 }, 145 { 146 desc: "Test 2: Attribute should not override header", 147 sandboxAttribute: "sandbox allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-top-navigation", 148 csp: "" 149 }, 150 { 151 desc: "Test 3: Header and attribute intersect", 152 sandboxAttribute: "allow-same-origin allow-scripts", 153 csp: "allow-forms allow-same-origin allow-scripts" 154 }, 155 { 156 desc: "Test 4: CSP sandbox sets the right flags (pt 1)", 157 csp: "alLOW-FORms ALLOW-pointer-lock allow-popups allow-same-origin allow-scripts ALLOW-TOP-NAVIGation" 158 }, 159 { 160 desc: "Test 5: CSP sandbox sets the right flags (pt 2)", 161 csp: "allow-same-origin allow-TOP-navigation" 162 }, 163 { 164 desc: "Test 6: CSP sandbox sets the right flags (pt 3)", 165 csp: "allow-FORMS ALLOW-scripts" 166 }, 167 { 168 desc: "Test 7: CSP sandbox sets the right flags (pt 4)", 169 csp: "" 170 }, 171 { 172 desc: "Test 8: CSP sandbox sets the right flags (pt 5)", 173 csp: null 174 }, 175 { 176 desc: "Test 9: Read-only header should not override attribute", 177 sandboxAttribute: "", 178 cspReportOnly: "allow-forms ALLOW-pointer-lock allow-POPUPS allow-same-origin ALLOW-scripts allow-top-NAVIGATION" 179 }, 180 { 181 desc: "Test 10: Read-only header should not override CSP header", 182 csp: "allow-forms allow-scripts", 183 cspReportOnly: "allow-forms aLlOw-PoInTeR-lOcK aLLow-pOPupS aLLoW-SaME-oRIgIN alLow-scripts allow-tOp-navigation" 184 }, 185 { 186 desc: "Test 11: Read-only header should not override attribute or CSP header", 187 sandboxAttribute: "allow-same-origin allow-scripts", 188 csp: "allow-forms allow-same-origin allow-scripts", 189 cspReportOnly: "allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-top-navigation" 190 }, 191 { 192 desc: "Test 12: CSP sandbox not affected by document.write()", 193 csp: "allow-scripts", 194 file: 'tests/dom/security/test/csp/file_iframe_sandbox_document_write.html' 195 }, 196 ].map(function(t) { return (new CSPFlagsTest(t.desc,t)); }); 197 198 199 var testCaseIndex = 0; 200 201 // Track ok messages from iframes 202 var childMessages = 0; 203 var totalChildMessages = 1; 204 205 206 // Check to see if we ran all the tests and received all messges 207 // from child iframes. If so, finish. 208 function tryFinish() { 209 if (testCaseIndex === testCases.length && childMessages === totalChildMessages){ 210 SimpleTest.finish(); 211 } 212 } 213 214 function runNextTest() { 215 216 tryFinish(); 217 218 if (testCaseIndex < testCases.length) { 219 testCases[testCaseIndex].runTest(); 220 testCaseIndex++; 221 } 222 } 223 224 function receiveMessage(event) { 225 ok(event.data.ok, event.data.desc); 226 childMessages++; 227 tryFinish(); 228 } 229 230 window.addEventListener("message", receiveMessage); 231 232 addLoadEvent(runNextTest); 233 </script> 234 <body> 235 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=671389">Mozilla Bug 671389</a> - Implement CSP sandbox directive 236 <p id="display"></p> 237 <div id="content"> 238 </div> 239 </body> 240 </html>