Bug 1198572 - Add telemetry for how often HSTS would fix mixed content problems r=smaug r=tanvi
authorRichard Barnes <rbarnes@mozilla.com>
Wed, 09 Sep 2015 15:14:27 -0400
changeset 294258 10f7ba9106b688a53bdc2e63489e13a5934f650b
parent 294257 a6163cb891f8211b7810983813cf3107d1549e00
child 294259 10ff4337ccece2d8fbc296ee35a5d991f4e8e362
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, tanvi
bugs1198572
milestone43.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 1198572 - Add telemetry for how often HSTS would fix mixed content problems r=smaug r=tanvi
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
dom/ipc/moz.build
dom/security/moz.build
dom/security/nsMixedContentBlocker.cpp
dom/security/nsMixedContentBlocker.h
toolkit/components/telemetry/Histograms.json
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -137,16 +137,17 @@
 #include "nsISupportsPrimitives.h"
 #include "nsISystemMessagesInternal.h"
 #include "nsITimer.h"
 #include "nsIURIFixup.h"
 #include "nsIWindowWatcher.h"
 #include "nsIXULRuntime.h"
 #include "gfxDrawable.h"
 #include "ImageOps.h"
+#include "mozilla/dom/nsMixedContentBlocker.h"
 #include "nsMemoryInfoDumper.h"
 #include "nsMemoryReporterManager.h"
 #include "nsServiceManagerUtils.h"
 #include "nsStyleSheetService.h"
 #include "nsThreadUtils.h"
 #include "nsToolkitCompsCID.h"
 #include "nsWidgetsCID.h"
 #include "PreallocatedProcessManager.h"
@@ -4171,16 +4172,27 @@ ContentParent::RecvIsSecureURI(const uin
     if (!ourURI) {
         return false;
     }
     nsresult rv = sss->IsSecureURI(type, ourURI, flags, isSecureURI);
     return NS_SUCCEEDED(rv);
 }
 
 bool
+ContentParent::RecvAccumulateMixedContentHSTS(const URIParams& aURI, const bool& aActive)
+{
+    nsCOMPtr<nsIURI> ourURI = DeserializeURI(aURI);
+    if (!ourURI) {
+        return false;
+    }
+    nsMixedContentBlocker::AccumulateMixedContentHSTS(ourURI, aActive);
+    return true;
+}
+
+bool
 ContentParent::RecvLoadURIExternal(const URIParams& uri)
 {
     nsCOMPtr<nsIExternalProtocolService> extProtService(do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
     if (!extProtService) {
         return true;
     }
     nsCOMPtr<nsIURI> ourURI = DeserializeURI(uri);
     if (!ourURI) {
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -621,16 +621,18 @@ private:
     virtual bool DeallocPCrashReporterParent(PCrashReporterParent* crashreporter) override;
 
     virtual bool RecvGetRandomValues(const uint32_t& length,
                                      InfallibleTArray<uint8_t>* randomValues) override;
 
     virtual bool RecvIsSecureURI(const uint32_t& aType, const URIParams& aURI,
                                  const uint32_t& aFlags, bool* aIsSecureURI) override;
 
+    virtual bool RecvAccumulateMixedContentHSTS(const URIParams& aURI, const bool& aActive) override;
+
     virtual bool DeallocPHalParent(PHalParent*) override;
 
     virtual PIccParent* AllocPIccParent(const uint32_t& aServiceId) override;
     virtual bool DeallocPIccParent(PIccParent* aActor) override;
 
     virtual PMemoryReportRequestParent*
     AllocPMemoryReportRequestParent(const uint32_t& aGeneration,
                                     const bool &aAnonymize,
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -746,16 +746,18 @@ parent:
     prio(urgent) sync GetRandomValues(uint32_t length)
         returns (uint8_t[] randomValues);
 
     async GetSystemMemory(uint64_t getterId);
 
     sync IsSecureURI(uint32_t type, URIParams uri, uint32_t flags)
         returns (bool isSecureURI);
 
+    async AccumulateMixedContentHSTS(URIParams uri, bool active);
+
     sync GetLookAndFeelCache()
         returns (LookAndFeelInt[] lookAndFeelIntCache);
 
     prio(urgent) async PHal();
 
     PIcc(uint32_t serviceId);
 
     PMobileConnection(uint32_t clientId);
@@ -783,17 +785,17 @@ parent:
 
     PMedia();
 
     PBluetooth();
 
     PFMRadio();
 
     PWebrtcGlobal();
-    
+
     PPresentation();
 
     // Services remoting
 
     async StartVisitedQuery(URIParams uri);
     async VisitURI(URIParams uri, OptionalURIParams referrer, uint32_t flags);
     async SetURITitle(URIParams uri, nsString title);
 
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -129,16 +129,17 @@ LOCAL_INCLUDES += [
     '/dom/bluetooth/common',
     '/dom/bluetooth/ipc',
     '/dom/devicestorage',
     '/dom/filesystem',
     '/dom/fmradio/ipc',
     '/dom/geolocation',
     '/dom/media/webspeech/synth/ipc',
     '/dom/mobilemessage/ipc',
+    '/dom/security',
     '/dom/storage',
     '/dom/workers',
     '/editor/libeditor',
     '/embedding/components/printingui/ipc',
     '/extensions/cookie',
     '/extensions/spellcheck/src',
     '/gfx/2d',
     '/hal/sandbox',
--- a/dom/security/moz.build
+++ b/dom/security/moz.build
@@ -28,17 +28,19 @@ UNIFIED_SOURCES += [
     'nsCSPParser.cpp',
     'nsCSPService.cpp',
     'nsCSPUtils.cpp',
     'nsMixedContentBlocker.cpp',
     'SRICheck.cpp',
     'SRIMetadata.cpp',
 ]
 
+include('/ipc/chromium/chromium-config.mozbuild')
+
 FINAL_LIBRARY = 'xul'
 LOCAL_INCLUDES += [
     '/caps',
     '/netwerk/base',
 ]
 
 if CONFIG['GNU_CC']:
-    CFLAGS += ['-Wshadow', '-Wformat-security']
-    CXXFLAGS += ['-Wshadow', '-Wformat-security']
+    CFLAGS += ['-Wformat-security']
+    CXXFLAGS += ['-Wformat-security']
--- a/dom/security/nsMixedContentBlocker.cpp
+++ b/dom/security/nsMixedContentBlocker.cpp
@@ -27,18 +27,23 @@
 #include "nsIDocumentLoader.h"
 #include "nsIWebNavigation.h"
 #include "nsLoadGroup.h"
 #include "nsIScriptError.h"
 #include "nsIURI.h"
 #include "nsIChannelEventSink.h"
 #include "nsAsyncRedirectVerifyHelper.h"
 #include "mozilla/LoadInfo.h"
+#include "nsISiteSecurityService.h"
 
 #include "mozilla/Logging.h"
+#include "mozilla/Telemetry.h"
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/ipc/URIUtils.h"
+
 
 using namespace mozilla;
 
 enum nsMixedContentBlockerMessageType {
   eBlocked = 0x00,
   eUserOverride = 0x01
 };
 
@@ -337,17 +342,17 @@ nsMixedContentBlocker::ShouldLoad(uint32
                                   nsISupports* aExtra,
                                   nsIPrincipal* aRequestPrincipal,
                                   int16_t* aDecision)
 {
   // We pass in false as the first parameter to ShouldLoad(), because the
   // callers of this method don't know whether the load went through cached
   // image redirects.  This is handled by direct callers of the static
   // ShouldLoad.
-  nsresult rv = ShouldLoad(false,   //aHadInsecureImageRedirect
+  nsresult rv = ShouldLoad(false,   // aHadInsecureImageRedirect
                            aContentType,
                            aContentLocation,
                            aRequestingLocation,
                            aRequestingContext,
                            aMimeGuess,
                            aExtra,
                            aRequestPrincipal,
                            aDecision);
@@ -376,17 +381,16 @@ nsMixedContentBlocker::ShouldLoad(bool a
   MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternal(aContentType),
              "We should only see external content policy types here.");
 
   // Assume active (high risk) content and blocked by default
   MixedContentTypes classification = eMixedScript;
   // Make decision to block/reject by default
   *aDecision = REJECT_REQUEST;
 
-
   // Notes on non-obvious decisions:
   //
   // TYPE_DTD: A DTD can contain entity definitions that expand to scripts.
   //
   // TYPE_FONT: The TrueType hinting mechanism is basically a scripting
   // language that gets interpreted by the operating system's font rasterizer.
   // Mixed content web fonts are relatively uncommon, and we can can fall back
   // to built-in fonts with minimal disruption in almost all cases.
@@ -713,16 +717,43 @@ nsMixedContentBlocker::ShouldLoad(bool a
   // If there is no securityUI, document doesn't have a security state.
   // Allow load and return early.
   if (!securityUI) {
     *aDecision = nsIContentPolicy::ACCEPT;
     return NS_OK;
   }
   nsresult stateRV = securityUI->GetState(&state);
 
+  // At this point we know that the request is mixed content, and the only
+  // question is whether we block it.  Record telemetry at this point as to
+  // whether HSTS would have fixed things by making the content location
+  // into an HTTPS URL.
+  //
+  // Note that we count this for redirects as well as primary requests. This
+  // will cause some degree of double-counting, especially when mixed content
+  // is not blocked (e.g., for images).  For more detail, see:
+  //   https://bugzilla.mozilla.org/show_bug.cgi?id=1198572#c19
+  //
+  // We do not count requests aHadInsecureImageRedirect=true, since these are
+  // just an artifact of the image caching system.
+  bool active = (classification == eMixedScript);
+  if (!aHadInsecureImageRedirect) {
+    if (XRE_IsParentProcess()) {
+      AccumulateMixedContentHSTS(aContentLocation, active);
+    } else {
+      // Ask the parent process to do the same call
+      mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
+      if (cc) {
+        mozilla::ipc::URIParams uri;
+        SerializeURI(aContentLocation, uri);
+        cc->SendAccumulateMixedContentHSTS(uri, active);
+      }
+    }
+  }
+
   // If the content is display content, and the pref says display content should be blocked, block it.
   if (sBlockMixedDisplay && classification == eMixedDisplay) {
     if (allowMixedContent) {
       LogMixedContentMessage(classification, aContentLocation, rootDoc, eUserOverride);
       *aDecision = nsIContentPolicy::ACCEPT;
       // See if mixed display content has already loaded on the page or if the state needs to be updated here.
       // If mixed display hasn't loaded previously, then we need to call OnSecurityChange() to update the UI.
       if (rootDoc->GetHasMixedDisplayContentLoaded()) {
@@ -852,8 +883,59 @@ nsMixedContentBlocker::ShouldProcess(uin
        return NS_ERROR_FAILURE;
     }
   }
 
   return ShouldLoad(aContentType, aContentLocation, aRequestingLocation,
                     aRequestingContext, aMimeGuess, aExtra, aRequestPrincipal,
                     aDecision);
 }
+
+enum MixedContentHSTSState {
+  MCB_HSTS_PASSIVE_NO_HSTS   = 0,
+  MCB_HSTS_PASSIVE_WITH_HSTS = 1,
+  MCB_HSTS_ACTIVE_NO_HSTS    = 2,
+  MCB_HSTS_ACTIVE_WITH_HSTS  = 3
+};
+
+// Record information on when HSTS would have made mixed content not mixed
+// content (regardless of whether it was actually blocked)
+void
+nsMixedContentBlocker::AccumulateMixedContentHSTS(nsIURI* aURI, bool aActive)
+{
+  // This method must only be called in the parent, because
+  // nsSiteSecurityService is only available in the parent
+  if (!XRE_IsParentProcess()) {
+    MOZ_ASSERT(false);
+    return;
+  }
+
+  bool hsts;
+  nsresult rv;
+  nsCOMPtr<nsISiteSecurityService> sss = do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
+  if (NS_FAILED(rv)) {
+    return;
+  }
+  rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI, 0, &hsts);
+  if (NS_FAILED(rv)) {
+    return;
+  }
+
+  if (!aActive) {
+    if (!hsts) {
+      Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS,
+                            MCB_HSTS_PASSIVE_NO_HSTS);
+    }
+    else {
+      Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS,
+                            MCB_HSTS_PASSIVE_WITH_HSTS);
+    }
+  } else {
+    if (!hsts) {
+      Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS,
+                            MCB_HSTS_ACTIVE_NO_HSTS);
+    }
+    else {
+      Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS,
+                            MCB_HSTS_ACTIVE_WITH_HSTS);
+    }
+  }
+}
--- a/dom/security/nsMixedContentBlocker.h
+++ b/dom/security/nsMixedContentBlocker.h
@@ -54,13 +54,14 @@ public:
                              uint32_t aContentType,
                              nsIURI* aContentLocation,
                              nsIURI* aRequestingLocation,
                              nsISupports* aRequestingContext,
                              const nsACString& aMimeGuess,
                              nsISupports* aExtra,
                              nsIPrincipal* aRequestPrincipal,
                              int16_t* aDecision);
+  static void AccumulateMixedContentHSTS(nsIURI* aURI, bool aActive);
   static bool sBlockMixedScript;
   static bool sBlockMixedDisplay;
 };
 
 #endif /* nsMixedContentBlocker_h___ */
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -7329,16 +7329,23 @@
     "description": "Accumulates type of content (mixed, mixed passive, unmixed) per page load"
   },
   "MIXED_CONTENT_UNBLOCK_COUNTER": {
     "expires_in_version": "never",
     "kind": "enumerated",
     "n_values": 3,
     "description": "A simple counter of daily mixed-content unblock operations and top documents loaded"
   },
+  "MIXED_CONTENT_HSTS": {
+    "alert_emails": ["seceng@mozilla.org"],
+    "expires_in_version": "never",
+    "kind": "enumerated",
+    "n_values": 10,
+    "description": "How often would blocked mixed content be allowed if HSTS upgrades were allowed? 0=display/no-HSTS, 1=display/HSTS, 2=active/no-HSTS, 3=active/HSTS"
+  },
   "NTLM_MODULE_USED_2": {
     "expires_in_version": "never",
     "kind": "enumerated",
     "n_values": 8,
     "description": "The module used for the NTLM protocol (Windows_API, Kerberos, Samba_auth or Generic) and whether or not the authentication was used to connect to a proxy server. This data is collected only once per session (at first NTLM authentification) ; fixed version."
   },
   "FX_THUMBNAILS_BG_QUEUE_SIZE_ON_CAPTURE": {
     "expires_in_version": "default",