Bug 1069762 - Make CSP violation reports match the spec for redirects. r=sstamm, a=dveditz
authorChristoph Kerschbaumer <mozilla@christophkerschbaumer.com>
Fri, 17 Oct 2014 14:26:50 -0700
changeset 225997 b77384b124a4
parent 225996 1f1e5b70a075
child 226000 2231ed05a1b8
push id4100
push userryanvm@gmail.com
push date2014-11-07 17:03 +0000
treeherdermozilla-beta@b77384b124a4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssstamm, dveditz
bugs1069762
milestone34.0
Bug 1069762 - Make CSP violation reports match the spec for redirects. r=sstamm, a=dveditz
content/base/src/nsCSPContext.cpp
--- a/content/base/src/nsCSPContext.cpp
+++ b/content/base/src/nsCSPContext.cpp
@@ -178,18 +178,19 @@ nsCSPContext::ShouldLoad(nsContentPolicy
         CSPCONTEXTLOG(("nsCSPContext::ShouldLoad, nsIContentPolicy::REJECT_SERVER"));
         *outDecision = nsIContentPolicy::REJECT_SERVER;
       }
 
       // Do not send a report or notify observers if this is a preload - the
       // decision may be wrong due to the inability to get the nonce, and will
       // incorrectly fail the unit tests.
       if (!isPreload) {
+        nsCOMPtr<nsIURI> originalURI = do_QueryInterface(aExtra);
         this->AsyncReportViolation(aContentLocation,
-                                   mSelfURI,
+                                   originalURI,   /* in case of redirect originalURI is not null */
                                    violatedDirective,
                                    p,             /* policy index        */
                                    EmptyString(), /* no observer subject */
                                    EmptyString(), /* no source file      */
                                    EmptyString(), /* no script sample    */
                                    0);            /* no line number      */
       }
     }
@@ -411,17 +412,17 @@ nsCSPContext::GetAllowsHash(const nsAStr
     PR_BEGIN_MACRO                                                             \
     if (!mPolicies[p]->allows(nsIContentPolicy::TYPE_ ## contentPolicyType,    \
                               keyword, nonceOrHash))                           \
     {                                                                          \
       nsAutoString violatedDirective;                                          \
       mPolicies[p]->getDirectiveStringForContentType(                          \
                         nsIContentPolicy::TYPE_ ## contentPolicyType,          \
                         violatedDirective);                                    \
-      this->AsyncReportViolation(selfISupports, mSelfURI, violatedDirective, p, \
+      this->AsyncReportViolation(selfISupports, nullptr, violatedDirective, p, \
                                  NS_LITERAL_STRING(observerTopic),             \
                                  aSourceFile, aScriptSample, aLineNum);        \
     }                                                                          \
     PR_END_MACRO;                                                              \
     break
 
 /**
  * For each policy, log any violation on the Error Console and send a report
@@ -567,16 +568,33 @@ nsCSPContext::SetRequestContext(nsIURI* 
     else {
       NS_WARNING("Channel provided to SetRequestContext is not an nsIHttpChannel so referrer is not available for reporting." );
     }
   }
 
   return NS_OK;
 }
 
+/**
+ * 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
+ *        the directive that was violated (string).
+ * @param aSourceFile
+ *        name of the file containing the inline script violation
+ * @param aScriptSample
+ *        a sample of the violating inline script
+ * @param aLineNum
+ *        source line number of the violation (if available)
+ */
 nsresult
 nsCSPContext::SendReports(nsISupports* aBlockedContentSource,
                           nsIURI* aOriginalURI,
                           nsAString& aViolatedDirective,
                           uint32_t aViolatedPolicyIndex,
                           nsAString& aSourceFile,
                           nsAString& aScriptSample,
                           uint32_t aLineNum)
@@ -596,37 +614,43 @@ 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) {
-      uri->GetSpecIgnoringRef(reportBlockedURI);
+      // 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);
+      }
     } 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
-  if (aOriginalURI) {
-    nsAutoCString reportDocumentURI;
-    aOriginalURI->GetSpecIgnoringRef(reportDocumentURI);
-    report.mCsp_report.mDocument_uri = NS_ConvertUTF8toUTF16(reportDocumentURI);
-  }
+  nsAutoCString reportDocumentURI;
+  mSelfURI->GetSpecIgnoringRef(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;
 
   // referrer
@@ -725,17 +749,17 @@ nsCSPContext::SendReports(nsISupports* a
     int16_t shouldLoad = nsIContentPolicy::ACCEPT;
     nsCOMPtr<nsIContentPolicy> cp = do_GetService(NS_CONTENTPOLICY_CONTRACTID);
     if (!cp) {
       return NS_ERROR_FAILURE;
     }
 
     rv = cp->ShouldLoad(nsIContentPolicy::TYPE_CSP_REPORT,
                         reportURI,
-                        aOriginalURI,
+                        mSelfURI,
                         nullptr,        // Context
                         EmptyCString(), // mime type
                         nullptr,        // Extra parameter
                         nullptr,        // optional request principal
                         &shouldLoad);
 
     // refuse to load if we can't do a security check
     NS_ENSURE_SUCCESS(rv, rv);
@@ -1038,17 +1062,17 @@ nsCSPContext::PermitsAncestry(nsIDocShel
                                  EmptyString(), // no nonce
                                  violatedDirective)) {
         // Policy is violated
         // Send reports, but omit the ancestor URI if cross-origin as per spec
         // (it is a violation of the same-origin policy).
         bool okToSendAncestor = NS_SecurityCompareURIs(ancestorsArray[a], mSelfURI, true);
 
         this->AsyncReportViolation((okToSendAncestor ? ancestorsArray[a] : nullptr),
-                                   mSelfURI,
+                                   nullptr,       /* originalURI in case of redirect */
                                    violatedDirective,
                                    i,             /* policy index        */
                                    EmptyString(), /* no observer subject */
                                    EmptyString(), /* no source file      */
                                    EmptyString(), /* no script sample    */
                                    0);            /* no line number      */
         *outPermitsAncestry = false;
       }