Bug 1252829 - CSP Telemetry, r=ckerschb, p=bsmedberg
MozReview-Commit-ID: CiNAxh2ZrHB
--- 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"