Bug 1198422 - CSP: Test fallback for nonce-src and hash-src. r=dveditz, a=sledru
authorChristoph Kerschbaumer <mozilla@christophkerschbaumer.com>
Thu, 27 Aug 2015 09:02:32 -0700
changeset 289026 8f5c669a887e5111dbce9884145fe278e3e1afad
parent 289025 7f3e8375ff3906657deb1bb4162a20238b716696
child 289027 63e48f89ff5caca7c4f99d6909d16038f5ac0cea
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdveditz, sledru
bugs1198422
milestone42.0a2
Bug 1198422 - CSP: Test fallback for nonce-src and hash-src. r=dveditz, a=sledru
dom/security/test/csp/file_ignore_unsafe_inline_multiple_policies_server.sjs
dom/security/test/csp/mochitest.ini
dom/security/test/csp/test_ignore_unsafe_inline.html
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/file_ignore_unsafe_inline_multiple_policies_server.sjs
@@ -0,0 +1,56 @@
+// custom *.sjs file specifically for the needs of:
+// * Bug 1004703 - ignore 'unsafe-inline' if nonce- or hash-source specified
+// * Bug 1198422: should not block inline script if default-src is not specified
+
+Components.utils.import("resource://gre/modules/NetUtil.jsm");
+
+function loadHTMLFromFile(path) {
+  // Load the HTML to return in the response from file.
+  // Since it's relative to the cwd of the test runner, we start there and
+  // append to get to the actual path of the file.
+  var testHTMLFile =
+    Components.classes["@mozilla.org/file/directory_service;1"].
+    getService(Components.interfaces.nsIProperties).
+    get("CurWorkD", Components.interfaces.nsILocalFile);
+  var dirs = path.split("/");
+  for (var i = 0; i < dirs.length; i++) {
+    testHTMLFile.append(dirs[i]);
+  }
+  var testHTMLFileStream =
+    Components.classes["@mozilla.org/network/file-input-stream;1"].
+    createInstance(Components.interfaces.nsIFileInputStream);
+  testHTMLFileStream.init(testHTMLFile, -1, 0, 0);
+  var testHTML = NetUtil.readInputStreamToString(testHTMLFileStream, testHTMLFileStream.available());
+  return testHTML;
+}
+
+
+function handleRequest(request, response)
+{
+  var query = {};
+  request.queryString.split('&').forEach(function (val) {
+    var [name, value] = val.split('=');
+    query[name] = unescape(value);
+  });
+
+  var csp1 = (query['csp1']) ? unescape(query['csp1']) : "";
+  var csp2 = (query['csp2']) ? unescape(query['csp2']) : "";
+  var file = unescape(query['file']);
+
+  // avoid confusing cache behaviors
+  response.setHeader("Cache-Control", "no-cache", false);
+
+  // deliver the CSP encoded in the URI
+  // please note that comma separation of two policies
+  // acts like sending *two* separate policies
+  var csp = csp1;
+  if (csp2 !== "") {
+    csp += ", " + csp2;
+  }
+  response.setHeader("Content-Security-Policy", csp, false);
+
+  // Send HTML to test allowed/blocked behaviors
+  response.setHeader("Content-Type", "text/html", false);
+
+  response.write(loadHTMLFromFile(file));
+}
--- a/dom/security/test/csp/mochitest.ini
+++ b/dom/security/test/csp/mochitest.ini
@@ -86,16 +86,17 @@ support-files =
   file_bug941404_xhr.html
   file_bug941404_xhr.html^headers^
   file_hash_source.html
   file_dual_header_testserver.sjs
   file_hash_source.html^headers^
   file_scheme_relative_sources.js
   file_scheme_relative_sources.sjs
   file_ignore_unsafe_inline.html
+  file_ignore_unsafe_inline_multiple_policies_server.sjs
   file_self_none_as_hostname_confusion.html
   file_self_none_as_hostname_confusion.html^headers^
   file_path_matching.html
   file_path_matching_incl_query.html
   file_path_matching.js
   file_path_matching_redirect.html
   file_path_matching_redirect_server.sjs
   file_testserver.sjs
--- a/dom/security/test/csp/test_ignore_unsafe_inline.html
+++ b/dom/security/test/csp/test_ignore_unsafe_inline.html
@@ -16,53 +16,63 @@ SimpleTest.waitForExplicitFinish();
 /* Description of the test:
  * We load a page that contains three scripts using different policies
  * and make sure 'unsafe-inline' is ignored within script-src if hash-source
  * or nonce-source is specified.
  *
  * The expected output of each test is a sequence of chars.
  * E.g. the default char we expect is 'a', depending on what inline scripts
  * are allowed to run we also expect 'b', 'c', 'd'.
+ *
+ * The test also covers the handling of multiple policies where the second
+ * policy makes use of a directive that should *not* fallback to
+ * default-src, see Bug 1198422.
  */
 
-var POLICY_PREFIX = "default-src 'none'; script-src ";
+const POLICY_PREFIX = "default-src 'none'; script-src ";
 
 var tests = [
   {
-    policy: POLICY_PREFIX + "'unsafe-inline'",
+    policy1: POLICY_PREFIX + "'unsafe-inline'",
+    policy2: "frame-ancestors 'self'",
     description: "'unsafe-inline' allows all scripts to execute",
     file: "file_ignore_unsafe_inline.html",
     result: "abcd",
   },
   {
-    policy: POLICY_PREFIX + "'unsafe-inline' 'sha256-uJXAPKP5NZxnVMZMUkDofh6a9P3UMRc1CRTevVPS/rI='",
+    policy1: POLICY_PREFIX + "'unsafe-inline' 'sha256-uJXAPKP5NZxnVMZMUkDofh6a9P3UMRc1CRTevVPS/rI='",
+    policy2: "base-uri http://mochi.test",
     description: "defining a hash should only allow one script to execute",
     file: "file_ignore_unsafe_inline.html",
     result: "ac",
   },
   {
-    policy: POLICY_PREFIX + "'unsafe-inline' 'nonce-FooNonce'",
+    policy1: POLICY_PREFIX + "'unsafe-inline' 'nonce-FooNonce'",
+    policy2: "form-action 'none'",
     description: "defining a nonce should only allow one script to execute",
     file: "file_ignore_unsafe_inline.html",
     result: "ad",
   },
   {
-    policy: POLICY_PREFIX + "'unsafe-inline' 'sha256-uJXAPKP5NZxnVMZMUkDofh6a9P3UMRc1CRTevVPS/rI=' 'nonce-FooNonce'",
+    policy1: POLICY_PREFIX + "'unsafe-inline' 'sha256-uJXAPKP5NZxnVMZMUkDofh6a9P3UMRc1CRTevVPS/rI=' 'nonce-FooNonce'",
+    policy2: "upgrade-insecure-requests",
     description: "defining hash and nonce should allow two scripts to execute",
     file: "file_ignore_unsafe_inline.html",
     result: "acd",
   },
   {
-    policy: POLICY_PREFIX + "'unsafe-inline' 'sha256-uJXAPKP5NZxnVMZMUkDofh6a9P3UMRc1CRTevVPS/rI=' 'nonce-FooNonce' 'unsafe-inline'",
+    policy1: POLICY_PREFIX + "'unsafe-inline' 'sha256-uJXAPKP5NZxnVMZMUkDofh6a9P3UMRc1CRTevVPS/rI=' 'nonce-FooNonce' 'unsafe-inline'",
+    policy2: "referrer origin",
     description: "defining hash, nonce and 'unsafe-inline' twice should still only allow two scripts to execute",
     file: "file_ignore_unsafe_inline.html",
     result: "acd",
   },
   {
-    policy: "default-src 'unsafe-inline' 'sha256-uJXAPKP5NZxnVMZMUkDofh6a9P3UMRc1CRTevVPS/rI=' 'nonce-FooNonce' ",
+    policy1: "default-src 'unsafe-inline' 'sha256-uJXAPKP5NZxnVMZMUkDofh6a9P3UMRc1CRTevVPS/rI=' 'nonce-FooNonce' ",
+    policy2: "sandbox allow-forms",
     description: "unsafe-inline should *not* be ignored within default-src even if hash or nonce is specified",
     file: "file_ignore_unsafe_inline.html",
     result: "abcd",
   },
 ];
 
 var counter = 0;
 var curTest;
@@ -70,22 +80,24 @@ var curTest;
 function loadNextTest() {
   if (counter == tests.length) {
     document.getElementById("testframe").removeEventListener("load", test, false);
     SimpleTest.finish();
     return;
   }
 
   curTest = tests[counter++];
-  var src = "file_testserver.sjs?file=";
+  var src = "file_ignore_unsafe_inline_multiple_policies_server.sjs?file=";
   // append the file that should be served
   src += escape("tests/dom/security/test/csp/" + curTest.file);
 
-  // append the CSP that should be used to serve the file
-  src += "&csp=" + escape(curTest.policy);
+  // append the first CSP that should be used to serve the file
+  src += "&csp1=" + escape(curTest.policy1);
+  // append the second CSP that should be used to serve the file
+  src += "&csp2=" + escape(curTest.policy2);
 
   document.getElementById("testframe").addEventListener("load", test, false);
   document.getElementById("testframe").src = src;
 }
 
 function test() {
   try {
     document.getElementById("testframe").removeEventListener('load', test, false);