Bug 1208946 - Strip URIs in CSP reports. r=dveditz, a=sylvestre
authorChristoph Kerschbaumer <mozilla@christophkerschbaumer.com>
Thu, 14 Jan 2016 12:36:50 -0800
changeset 310925 481ff8485da5dbf3a712b9d2b534c76758d1d226
parent 310924 5e13efb1f0b8e9f8263c7dbdb752cff6507b4c4c
child 310926 ac26deb3a325de82045cf1b633aa7f36567d0b86
push id5513
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 13:55:34 +0000
treeherdermozilla-beta@5ee97dd05b5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdveditz, sylvestre
bugs1208946
milestone45.0a2
Bug 1208946 - Strip URIs in CSP reports. r=dveditz, a=sylvestre
dom/security/nsCSPContext.cpp
--- a/dom/security/nsCSPContext.cpp
+++ b/dom/security/nsCSPContext.cpp
@@ -586,16 +586,17 @@ nsCSPContext::SetRequestContext(nsIDOMDo
   NS_PRECONDITION(aDOMDocument || aPrincipal,
                   "Can't set context without doc or principal");
   NS_ENSURE_ARG(aDOMDocument || aPrincipal);
 
   if (aDOMDocument) {
     nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDOMDocument);
     mLoadingContext = do_GetWeakReference(doc);
     mSelfURI = doc->GetDocumentURI();
+    mLoadingPrincipal = doc->NodePrincipal();
     doc->GetReferrer(mReferrer);
     mInnerWindowID = doc->InnerWindowID();
     // the innerWindowID is not available for CSPs delivered through the
     // header at the time setReqeustContext is called - let's queue up
     // console messages until it becomes available, see flushConsoleMessages
     mQueueUpMessages = !mInnerWindowID;
     mCallingChannelLoadGroup = doc->GetDocumentLoadGroup();
   }
@@ -664,16 +665,61 @@ nsCSPContext::logToConsole(const char16_
     return;
   }
   CSP_LogLocalizedStr(aName, aParams, aParamsLength, aSourceName,
                       aSourceLine, aLineNumber, aColumnNumber,
                       aSeverityFlag, "CSP", mInnerWindowID);
 }
 
 /**
+ * Strip URI for reporting according to:
+ * http://www.w3.org/TR/CSP/#violation-reports
+ *
+ * @param aURI
+ *        The uri to be stripped for reporting
+ * @param aProtectedResourcePrincipal
+ *        The loadingPrincipal of the protected resource
+ *        which is needed to enforce the SOP.
+ * @return ASCII serialization of the uri to be reported.
+ */
+void
+StripURIForReporting(nsIURI* aURI,
+                     nsIPrincipal* aProtectedResourcePrincipal,
+                     nsACString& outStrippedURI)
+{
+  // 1) If the origin of uri is a globally unique identifier (for example,
+  // aURI has a scheme of data, blob, or filesystem), then return the
+  // ASCII serialization of uri’s scheme.
+  bool isHttp =
+    (NS_SUCCEEDED(aURI->SchemeIs("http", &isHttp)) && isHttp) ||
+    (NS_SUCCEEDED(aURI->SchemeIs("https", &isHttp)) && isHttp);
+  if (!isHttp) {
+    // not strictly spec compliant, but what we really care about is
+    // http/https. If it's not http/https, then treat aURI as if
+    // it's a globally unique identifier and just return the scheme.
+    aURI->GetScheme(outStrippedURI);
+    return;
+  }
+
+  // 2) If the origin of uri is not the same as the origin of the protected
+  // resource, then return the ASCII serialization of uri’s origin.
+  bool sameOrigin =
+    NS_SUCCEEDED(aProtectedResourcePrincipal->CheckMayLoad(aURI, false, false));
+  if (!sameOrigin) {
+    // cross origin redirects also fall into this category, see:
+    // http://www.w3.org/TR/CSP/#violation-reports
+    aURI->GetPrePath(outStrippedURI);
+    return;
+  }
+
+  // 3) Return uri, with any fragment component removed.
+  aURI->GetSpecIgnoringRef(outStrippedURI);
+}
+
+/**
  * Sends CSP violation reports to all sources listed under report-uri.
  *
  * @param aBlockedContentSource
  *        Either a CSP Source (like 'self', as string) or nsIURI: the source
  *        of the violation.
  * @param aOriginalUri
  *        The original URI if the blocked content is a redirect, else null
  * @param aViolatedDirective
@@ -709,42 +755,34 @@ nsCSPContext::SendReports(nsISupports* a
   nsresult rv;
 
   // blocked-uri
   if (aBlockedContentSource) {
     nsAutoCString reportBlockedURI;
     nsCOMPtr<nsIURI> uri = do_QueryInterface(aBlockedContentSource);
     // could be a string or URI
     if (uri) {
-      // aOriginalURI will only be *not* null in case of a redirect in which
-      // case aOriginalURI is the uri before the redirect.
-      if (aOriginalURI) {
-        // do not report anything else than the origin in case of a redirect, see:
-        // http://www.w3.org/TR/CSP/#violation-reports
-        uri->GetPrePath(reportBlockedURI);
-      } else {
-        uri->GetSpecIgnoringRef(reportBlockedURI);
-      }
+      StripURIForReporting(uri, mLoadingPrincipal, reportBlockedURI);
     } else {
       nsCOMPtr<nsISupportsCString> cstr = do_QueryInterface(aBlockedContentSource);
       if (cstr) {
         cstr->GetData(reportBlockedURI);
       }
     }
     if (reportBlockedURI.IsEmpty()) {
       // this can happen for frame-ancestors violation where the violating
       // ancestor is cross-origin.
       NS_WARNING("No blocked URI (null aBlockedContentSource) for CSP violation report.");
     }
     report.mCsp_report.mBlocked_uri = NS_ConvertUTF8toUTF16(reportBlockedURI);
   }
 
   // document-uri
   nsAutoCString reportDocumentURI;
-  mSelfURI->GetSpecIgnoringRef(reportDocumentURI);
+  StripURIForReporting(mSelfURI, mLoadingPrincipal, reportDocumentURI);
   report.mCsp_report.mDocument_uri = NS_ConvertUTF8toUTF16(reportDocumentURI);
 
   // original-policy
   nsAutoString originalPolicy;
   rv = this->GetPolicy(aViolatedPolicyIndex, originalPolicy);
   NS_ENSURE_SUCCESS(rv, rv);
   report.mCsp_report.mOriginal_policy = originalPolicy;