Bug 1252829 - CSP Telemetry, r=ckerschb, p=bsmedberg draft
authorFranziskus Kiefer <franziskuskiefer@gmail.com>
Wed, 02 Mar 2016 13:00:09 +0100
changeset 340997 b800e0831b29bd49de09cd504eae7b39546b8b99
parent 340857 7773387a9a2f1fd10e4424ea923c6185063f620b
child 516312 af54b2764fe523c3cbe32f51b6762b777eeb9060
push id13114
push userfranziskuskiefer@gmail.com
push dateWed, 16 Mar 2016 10:52:28 +0000
reviewersckerschb
bugs1252829
milestone48.0a1
Bug 1252829 - CSP Telemetry, r=ckerschb, p=bsmedberg MozReview-Commit-ID: CiNAxh2ZrHB
dom/base/nsDocument.cpp
dom/base/nsIDocument.h
dom/security/nsCSPContext.cpp
dom/security/nsCSPContext.h
dom/security/nsCSPParser.cpp
toolkit/components/telemetry/Histograms.json
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1578,16 +1578,27 @@ nsDocument::~nsDocument()
       // record mixed object subrequest telemetry
       if (mHasMixedContentObjectSubrequest) {
         /* mixed object subrequest loaded on page*/
         Accumulate(Telemetry::MIXED_CONTENT_OBJECT_SUBREQUEST, 1);
       } else {
         /* no mixed object subrequests loaded on page*/
         Accumulate(Telemetry::MIXED_CONTENT_OBJECT_SUBREQUEST, 0);
       }
+
+      // record CSP telemetry on this document
+      if (mHasCSP) {
+        Accumulate(Telemetry::CSP_DOCUMENTS_COUNT, 1);
+      }
+      if (mHasUnsafeInlineCSP) {
+        Accumulate(Telemetry::CSP_UNSAFE_INLINE_DOCUMENTS_COUNT, 1);
+      }
+      if (mHasUnsafeEvalCSP) {
+        Accumulate(Telemetry::CSP_UNSAFE_EVAL_DOCUMENTS_COUNT, 1);
+      }
     }
   }
 
   ReportUseCounters();
 
   mInDestructor = true;
   mInUnlinkOrDeletion = true;
 
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -614,16 +614,40 @@ public:
    * Set the mixed content object subrequest flag for this document.
    */
   void SetHasMixedContentObjectSubrequest(bool aHasMixedContentObjectSubrequest)
   {
     mHasMixedContentObjectSubrequest = aHasMixedContentObjectSubrequest;
   }
 
   /**
+   * Set CSP flag for this document.
+   */
+  void SetHasCSP(bool aHasCSP)
+  {
+    mHasCSP = aHasCSP;
+  }
+
+  /**
+   * Set unsafe-inline CSP flag for this document.
+   */
+  void SetHasUnsafeInlineCSP(bool aHasUnsafeInlineCSP)
+  {
+    mHasUnsafeInlineCSP = aHasUnsafeInlineCSP;
+  }
+
+  /**
+   * Set unsafe-eval CSP flag for this document.
+   */
+  void SetHasUnsafeEvalCSP(bool aHasUnsafeEvalCSP)
+  {
+    mHasUnsafeEvalCSP = aHasUnsafeEvalCSP;
+  }
+
+  /**
    * Get tracking content blocked flag for this document.
    */
   bool GetHasTrackingContentBlocked()
   {
     return mHasTrackingContentBlocked;
   }
 
   /**
@@ -2914,16 +2938,25 @@ protected:
   bool mHasMixedDisplayContentLoaded : 1;
 
   // True if a document has blocked Mixed Display/Passive Content (see nsMixedContentBlocker.cpp)
   bool mHasMixedDisplayContentBlocked : 1;
 
   // True if a document loads a plugin object that attempts to load mixed content subresources through necko(see nsMixedContentBlocker.cpp)
   bool mHasMixedContentObjectSubrequest : 1;
 
+  // True if a document load has a CSP attached.
+  bool mHasCSP : 1;
+
+  // True if a document load has a CSP with unsafe-eval attached.
+  bool mHasUnsafeEvalCSP : 1;
+
+  // True if a document load has a CSP with unsafe-inline attached.
+  bool mHasUnsafeInlineCSP : 1;
+
   // True if a document has blocked Tracking Content
   bool mHasTrackingContentBlocked : 1;
 
   // True if a document has loaded Tracking Content
   bool mHasTrackingContentLoaded : 1;
 
   // True if DisallowBFCaching has been called on this document.
   bool mBFCacheDisallowed : 1;
--- a/dom/security/nsCSPContext.cpp
+++ b/dom/security/nsCSPContext.cpp
@@ -596,16 +596,19 @@ nsCSPContext::SetRequestContext(nsIDOMDo
     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();
+
+    // set the flag on the document for CSP telemetry
+    doc->SetHasCSP(true);
   }
   else {
     NS_WARNING("No Document in SetRequestContext; can not query loadgroup; sending reports may fail.");
     mLoadingPrincipal = aPrincipal;
     mLoadingPrincipal->GetURI(getter_AddRefs(mSelfURI));
     // if no document is available, then it also does not make sense to queue console messages
     // sending messages to the browser conolse instead of the web console in that case.
     mQueueUpMessages = false;
--- a/dom/security/nsCSPContext.h
+++ b/dom/security/nsCSPContext.h
@@ -76,16 +76,20 @@ class nsCSPContext : public nsIContentSe
 
     // Hands off! Don't call this method unless you know what you
     // are doing. It's only supposed to be called from within
     // the principal destructor to avoid a tangling pointer.
     void clearLoadingPrincipal() {
       mLoadingPrincipal = nullptr;
     }
 
+    nsWeakPtr GetLoadingContext(){
+      return mLoadingContext;
+    }
+
   private:
     bool permitsInternal(CSPDirective aDir,
                          nsIURI* aContentLocation,
                          nsIURI* aOriginalURI,
                          const nsAString& aNonce,
                          bool aWasRedirected,
                          bool aIsPreload,
                          bool aSpecific,
--- a/dom/security/nsCSPParser.cpp
+++ b/dom/security/nsCSPParser.cpp
@@ -573,31 +573,39 @@ nsCSPParser::keywordSource()
 
   // Special case handling for 'self' which is not stored internally as a keyword,
   // but rather creates a nsCSPHostSrc using the selfURI
   if (CSP_IsKeyword(mCurToken, CSP_SELF)) {
     return CSP_CreateHostSrcFromURI(mSelfURI);
   }
 
   if (CSP_IsKeyword(mCurToken, CSP_UNSAFE_INLINE)) {
+      nsCOMPtr<nsIDocument> doc = do_QueryReferent(mCSPContext->GetLoadingContext());
+      if (doc) {
+        doc->SetHasUnsafeInlineCSP(true);
+      }
     // make sure script-src only contains 'unsafe-inline' once;
     // ignore duplicates and log warning
     if (mUnsafeInlineKeywordSrc) {
       const char16_t* params[] = { mCurToken.get() };
       logWarningErrorToConsole(nsIScriptError::warningFlag, "ignoringDuplicateSrc",
                                params, ArrayLength(params));
       return nullptr;
     }
     // cache if we encounter 'unsafe-inline' so we can invalidate (ignore) it in
     // case that script-src directive also contains hash- or nonce-.
     mUnsafeInlineKeywordSrc = new nsCSPKeywordSrc(CSP_KeywordToEnum(mCurToken));
     return mUnsafeInlineKeywordSrc;
   }
 
   if (CSP_IsKeyword(mCurToken, CSP_UNSAFE_EVAL)) {
+    nsCOMPtr<nsIDocument> doc = do_QueryReferent(mCSPContext->GetLoadingContext());
+    if (doc) {
+      doc->SetHasUnsafeEvalCSP(true);
+    }
     return new nsCSPKeywordSrc(CSP_KeywordToEnum(mCurToken));
   }
   return nullptr;
 }
 
 // host-source = [ scheme "://" ] host [ port ] [ path ]
 nsCSPHostSrc*
 nsCSPParser::hostSource()
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -3274,16 +3274,37 @@
   "URLCLASSIFIER_COMPLETE_REMOTE_STATUS": {
     "alert_emails": ["gcp@mozilla.com", "francois@mozilla.com"],
     "expires_in_version": "never",
     "kind": "enumerated",
     "n_values": 16,
     "bug_numbers": [1150921],
     "description": "Server HTTP status code from remote SafeBrowsing gethash lookups. (0=1xx, 1=200, 2=2xx, 3=204, 4=3xx, 5=400, 6=4xx, 7=403, 8=404, 9=408, 10=413, 11=5xx, 12=502|504|511, 13=503, 14=505, 15=Other)"
   },
+  "CSP_DOCUMENTS_COUNT": {
+    "alert_emails": ["seceng@mozilla.com"],
+    "bug_numbers": [1252829],
+    "expires_in_version": "55",
+    "kind": "count",
+    "description": "Number of unique pages that contain a CSP"
+  },
+  "CSP_UNSAFE_INLINE_DOCUMENTS_COUNT": {
+    "alert_emails": ["seceng@mozilla.com"],
+    "bug_numbers": [1252829],
+    "expires_in_version": "55",
+    "kind": "count",
+    "description": "Number of unique pages that contain an unsafe-inline CSP directive"
+  },
+  "CSP_UNSAFE_EVAL_DOCUMENTS_COUNT": {
+    "alert_emails": ["seceng@mozilla.com"],
+    "bug_numbers": [1252829],
+    "expires_in_version": "55",
+    "kind": "count",
+    "description": "Number of unique pages that contain an unsafe-eval CSP directive"
+  },
   "PLACES_PAGES_COUNT": {
     "expires_in_version": "never",
     "kind": "exponential",
     "low": 1000,
     "high": 150000,
     "n_buckets": 20,
     "releaseChannelCollection": "opt-out",
     "description": "PLACES: Number of unique pages"