Bug 916446 - TweetDeck web shows a blank page. r=sstamm
☠☠ backed out by d7d304e28da9 ☠ ☠
authorGarrett Robinson <grobinson@mozilla.com>
Tue, 17 Sep 2013 16:10:03 -0400
changeset 161360 d63424e06b3e161bf5baa141d0e1494f6c5a65de
parent 161359 6bfcffd02d97ef9cb013dc0c459d3d5d449a9b14
child 161361 f0cc00e701d708bd427fb3a024fd33600bb50f3d
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssstamm
bugs916446
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 916446 - TweetDeck web shows a blank page. r=sstamm CLOSED TREE
content/base/src/CSPUtils.jsm
content/base/test/csp/Makefile.in
content/base/test/csp/file_CSP_bug916446.html
content/base/test/csp/file_CSP_bug916446.html^headers^
content/base/test/csp/test_CSP_bug916446.html
--- a/content/base/src/CSPUtils.jsm
+++ b/content/base/src/CSPUtils.jsm
@@ -238,16 +238,18 @@ CSPRep.ALLOW_DIRECTIVE   = "allow";
   *        string rep of a CSP
   * @param self (optional)
   *        URI representing the "self" source
   * @param docRequest (optional)
   *        request for the parent document which may need to be suspended
   *        while the policy-uri is asynchronously fetched
   * @param csp (optional)
   *        the CSP object to update once the policy has been fetched
+  * @param reportOnly (optional)
+  *        whether or not this CSP is report-only (defaults to false)
   * @returns
   *        an instance of CSPRep
   */
 CSPRep.fromString = function(aStr, self, docRequest, csp, reportOnly) {
   if (typeof reportOnly === 'undefined') reportOnly = false;
   var SD = CSPRep.SRC_DIRECTIVES_OLD;
   var UD = CSPRep.URI_DIRECTIVES;
   var aCSPR = new CSPRep();
@@ -475,17 +477,18 @@ CSPRep.fromString = function(aStr, self,
                                              [dirname]));
 
   } // end directive: loop
 
   // the X-Content-Security-Policy syntax requires an allow or default-src
   // directive to be present.
   if (!aCSPR._directives[SD.DEFAULT_SRC]) {
     cspWarn(aCSPR, CSPLocalizer.getStr("allowOrDefaultSrcRequired"));
-    return CSPRep.fromString("default-src 'none'", selfUri);
+    return CSPRep.fromString("default-src 'none'", selfUri, docRequest, csp,
+                             reportOnly);
   }
   return aCSPR;
 };
 
 /**
   * Factory to create a new CSPRep, parsed from a string, compliant
   * with the CSP 1.0 spec.
   *
@@ -493,16 +496,18 @@ CSPRep.fromString = function(aStr, self,
   *        string rep of a CSP
   * @param self (optional)
   *        URI representing the "self" source
   * @param docRequest (optional)
   *        request for the parent document which may need to be suspended
   *        while the policy-uri is asynchronously fetched
   * @param csp (optional)
   *        the CSP object to update once the policy has been fetched
+  * @param reportOnly (optional)
+  *        whether or not this CSP is report-only (defaults to false)
   * @returns
   *        an instance of CSPRep
   */
 // When we deprecate our original CSP implementation, we rename this to
 // CSPRep.fromString and remove the existing CSPRep.fromString above.
 CSPRep.fromStringSpecCompliant = function(aStr, self, docRequest, csp, reportOnly) {
   if (typeof reportOnly === 'undefined') reportOnly = false;
 
--- a/content/base/test/csp/Makefile.in
+++ b/content/base/test/csp/Makefile.in
@@ -92,16 +92,19 @@ MOCHITEST_FILES := \
   test_CSP_bug888172.html \
   file_CSP_bug888172.html \
   file_CSP_bug888172.sjs \
   test_bug836922_npolicies.html \
   file_bug836922_npolicies.html \
   file_bug836922_npolicies.html^headers^ \
   file_bug836922_npolicies_violation.sjs \
   file_bug836922_npolicies_ro_violation.sjs \
+  test_CSP_bug916446.html \
+  file_CSP_bug916446.html \
+  file_CSP_bug916446.html^headers^ \
   $(NULL)
 
 MOCHITEST_CHROME_FILES := \
   test_csp_bug768029.html \
   test_csp_bug773891.html \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/content/base/test/csp/file_CSP_bug916446.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<html>
+  <body>
+    <ol>
+      <li id="inline-script">Inline script (green if allowed, black if blocked)</li>
+    </ol>
+
+    <script>
+      // Use inline script to set a style attribute
+      document.getElementById("inline-script").style.color = "rgb(0, 128, 0)";
+    </script>
+
+    <img src="file_CSP.sjs?testid=img_bad&type=img/png"></img>
+
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/csp/file_CSP_bug916446.html^headers^
@@ -0,0 +1,1 @@
+x-content-security-policy-report-only: options eval-script; script-src 'self' ; report-uri /csp_report
new file mode 100644
--- /dev/null
+++ b/content/base/test/csp/test_CSP_bug916446.html
@@ -0,0 +1,118 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Bug 916446</title>
+   <!--
+   test that an invalid report-only policy (a stripped down version of what
+   web.tweetdeck.com was serving) defaults to "default-src 'none'" but only
+   sends reports and is not accidentally enforced
+   -->
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:200px;height:200px;" id='testframe'></iframe>
+
+<script class="testbody" type="text/javascript">
+
+// This is used to watch the blocked data bounce off CSP and allowed data
+// get sent out to the wire.
+function examiner() {
+  SpecialPowers.addObserver(this, "csp-on-violate-policy", false);
+  SpecialPowers.addObserver(this, "http-on-modify-request", false);
+}
+examiner.prototype  = {
+  completedTests: 0,
+  totalTests: 4,
+
+  observe: function(subject, topic, data) {
+    // subject should be an nsURI, and should be either allowed or blocked.
+    if (!SpecialPowers.can_QI(subject))
+      return;
+
+    var testpat = new RegExp("testid=([a-z0-9_]+)");
+
+    if (topic === "http-on-modify-request") {
+      //these things were allowed by CSP
+      var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIHttpChannel"), "URI.asciiSpec");
+      if (!testpat.test(asciiSpec)) return;
+      var testid = testpat.exec(asciiSpec)[1];
+      if (testid === "img_bad") {
+        // img_bad should be *allowed* because the policy is report-only
+        ok(true, "Inline scripts should execute (because the policy is report-only)");
+        this.completedTests++;
+      }
+    }
+
+    if(topic === "csp-on-violate-policy") {
+      // these were blocked
+      try {
+        var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec");
+        if (!testpat.test(asciiSpec)) return;
+        var testid = testpat.exec(asciiSpec)[1];
+        if (testid === "img_bad") {
+          ok(true, "External loads should trigger a violation report (because the policy should fail closed to \"default-src 'none'\")");
+          this.completedTests++;
+        }
+      } catch (e) {
+        // if that fails, the subject is probably a string
+        violation_msg = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsISupportsCString"), "data");
+        if (/Inline Scripts will not execute/.test(violation_msg)) {
+          ok(true, "Inline scripts should trigger a violation report (because the policy should fail closed to \"default-src 'none'\")");
+          this.completedTests++;
+        }
+      }
+    }
+  },
+
+  // must eventually call this to remove the listener,
+  // or mochitests might get borked.
+  remove: function() {
+    SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+    SpecialPowers.removeObserver(this, "http-on-modify-request");
+  }
+}
+
+window.examiner = new examiner();
+
+function checkInlineScriptExecuted() {
+  var green = 'rgb(0, 128, 0)';
+  var black = 'rgb(0, 0, 0)';
+  var that = this;
+  function getElementColorById(id) {
+    return window.getComputedStyle(that.contentDocument.getElementById(id)).color;
+  }
+  if (getElementColorById('inline-script') === green) {
+    ok(true, "Inline scripts should execute (because the policy is report-only)");
+    window.examiner.completedTests++;
+  }
+
+  waitToFinish();
+}
+
+function waitToFinish() {
+  setTimeout(function wait() {
+    if (window.examiner.completedTests < window.examiner.totalTests) {
+        waitToFinish();
+    } else {
+      // Cleanup
+      window.examiner.remove();
+      SimpleTest.finish();
+    }
+  }, 10);
+}
+
+SimpleTest.waitForExplicitFinish();
+
+SpecialPowers.pushPrefEnv(
+  {'set':[["security.csp.speccompliant", false]]},
+  function() {
+    var testframe = document.getElementById('testframe');
+    testframe.src = 'file_CSP_bug916446.html';
+    testframe.addEventListener('load', checkInlineScriptExecuted);
+  }
+);
+</script>
+</pre>
+</body>
+</html>