Bug 1333651 - Part 2: Spoofing Navigator object when 'privacy.resistFingerprinting' is true. r?Ehsan,arthuredelstein draft
authorTim Huang <tihuang@mozilla.com>
Thu, 01 Jun 2017 14:54:59 +0800
changeset 596579 536ab4f3ca16618b6a4ae0f8da58fc646f697045
parent 596578 3f3177958f78a6f48f4551cf4d7df343b2994bdd
child 596580 b3c9aafcf47d28b0f661886b266b19fbe9e83bac
child 596625 353bed2bd49f9c8db5c53736c81f43b8485cc17d
push id64684
push userbmo:tihuang@mozilla.com
push dateMon, 19 Jun 2017 13:26:45 +0000
reviewersEhsan, arthuredelstein
bugs1333651
milestone56.0a1
Bug 1333651 - Part 2: Spoofing Navigator object when 'privacy.resistFingerprinting' is true. r?Ehsan,arthuredelstein This patch makes navigator object to return spoofed value for fields have fingerprintable concerns. This changes the worker navigator as well. MozReview-Commit-ID: E2SLNZRfuVP
dom/base/Navigator.cpp
dom/workers/WorkerNavigator.cpp
netwerk/protocol/http/nsHttpHandler.cpp
toolkit/components/resistfingerprinting/nsRFPService.h
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -56,16 +56,17 @@
 #include "mozilla/StaticPtr.h"
 #include "Connection.h"
 #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
 #include "nsGlobalWindow.h"
 #include "nsIIdleObserver.h"
 #include "nsIPermissionManager.h"
 #include "nsMimeTypes.h"
 #include "nsNetUtil.h"
+#include "nsRFPService.h"
 #include "nsStringStream.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIStringStream.h"
 #include "nsIHttpChannel.h"
 #include "nsIHttpChannelInternal.h"
 #include "TimeManager.h"
 #include "nsStreamUtils.h"
 #include "WidgetUtils.h"
@@ -460,16 +461,23 @@ Navigator::GetPlatform(nsAString& aPlatf
   }
 }
 
 void
 Navigator::GetOscpu(nsAString& aOSCPU, CallerType aCallerType,
                     ErrorResult& aRv) const
 {
   if (aCallerType != CallerType::System) {
+    // If fingerprinting resistance is on, we will spoof this value. See nsRFPService.h
+    // for details about spoofed values.
+    if (nsContentUtils::ShouldResistFingerprinting()) {
+      aOSCPU.AssignLiteral(SPOOFED_OSCPU);
+      return;
+    }
+
     const nsAdoptingString& override =
       Preferences::GetString("general.oscpu.override");
 
     if (override) {
       aOSCPU = override;
       return;
     }
   }
@@ -512,17 +520,17 @@ Navigator::GetProduct(nsAString& aProduc
   aProduct.AssignLiteral("Gecko");
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Navigator::GetProductSub(nsAString& aProductSub)
 {
   // Legacy build ID hardcoded for backward compatibility (bug 776376)
-  aProductSub.AssignLiteral("20100101");
+  aProductSub.AssignLiteral(LEGACY_BUILD_ID);
   return NS_OK;
 }
 
 nsMimeTypeArray*
 Navigator::GetMimeTypes(ErrorResult& aRv)
 {
   if (!mMimeTypes) {
     if (!mWindow) {
@@ -634,16 +642,22 @@ Navigator::OnLine()
   return !NS_IsOffline();
 }
 
 void
 Navigator::GetBuildID(nsAString& aBuildID, CallerType aCallerType,
                       ErrorResult& aRv) const
 {
   if (aCallerType != CallerType::System) {
+    // If fingerprinting resistance is on, we will spoof this value. See nsRFPService.h
+    // for details about spoofed values.
+    if (nsContentUtils::ShouldResistFingerprinting()) {
+      aBuildID.AssignLiteral(LEGACY_BUILD_ID);
+      return;
+    }
     const nsAdoptingString& override =
       Preferences::GetString("general.buildID.override");
 
     if (override) {
       aBuildID = override;
       return;
     }
   }
@@ -1764,16 +1778,22 @@ Navigator::GetWindowFromGlobal(JSObject*
 }
 
 nsresult
 Navigator::GetPlatform(nsAString& aPlatform, bool aUsePrefOverriddenValue)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (aUsePrefOverriddenValue) {
+    // If fingerprinting resistance is on, we will spoof this value. See nsRFPService.h
+    // for details about spoofed values.
+    if (nsContentUtils::ShouldResistFingerprinting()) {
+      aPlatform.AssignLiteral(SPOOFED_PLATFORM);
+      return NS_OK;
+    }
     const nsAdoptingString& override =
       mozilla::Preferences::GetString("general.platform.override");
 
     if (override) {
       aPlatform = override;
       return NS_OK;
     }
   }
@@ -1809,16 +1829,22 @@ Navigator::GetPlatform(nsAString& aPlatf
 }
 
 /* static */ nsresult
 Navigator::GetAppVersion(nsAString& aAppVersion, bool aUsePrefOverriddenValue)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (aUsePrefOverriddenValue) {
+    // If fingerprinting resistance is on, we will spoof this value. See nsRFPService.h
+    // for details about spoofed values.
+    if (nsContentUtils::ShouldResistFingerprinting()) {
+      aAppVersion.AssignLiteral(SPOOFED_APPVERSION);
+      return NS_OK;
+    }
     const nsAdoptingString& override =
       mozilla::Preferences::GetString("general.appversion.override");
 
     if (override) {
       aAppVersion = override;
       return NS_OK;
     }
   }
@@ -1846,16 +1872,23 @@ Navigator::GetAppVersion(nsAString& aApp
 }
 
 /* static */ void
 Navigator::AppName(nsAString& aAppName, bool aUsePrefOverriddenValue)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (aUsePrefOverriddenValue) {
+    // If fingerprinting resistance is on, we will spoof this value. See nsRFPService.h
+    // for details about spoofed values.
+    if (nsContentUtils::ShouldResistFingerprinting()) {
+      aAppName.AssignLiteral(SPOOFED_APPNAME);
+      return;
+    }
+
     const nsAdoptingString& override =
       mozilla::Preferences::GetString("general.appname.override");
 
     if (override) {
       aAppName = override;
       return;
     }
   }
@@ -1871,17 +1904,20 @@ Navigator::ClearUserAgentCache()
 
 nsresult
 Navigator::GetUserAgent(nsPIDOMWindowInner* aWindow,
                         bool aIsCallerChrome,
                         nsAString& aUserAgent)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  if (!aIsCallerChrome) {
+  // We will skip the override and pass to httpHandler to get spoofed userAgent
+  // when 'privacy.resistFingerprinting' is true.
+  if (!aIsCallerChrome &&
+      !nsContentUtils::ShouldResistFingerprinting()) {
     const nsAdoptingString& override =
       mozilla::Preferences::GetString("general.useragent.override");
 
     if (override) {
       aUserAgent = override;
       return NS_OK;
     }
   }
@@ -1896,17 +1932,21 @@ Navigator::GetUserAgent(nsPIDOMWindowInn
   nsAutoCString ua;
   rv = service->GetUserAgent(ua);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   CopyASCIItoUTF16(ua, aUserAgent);
 
-  if (!aWindow) {
+  // When the caller is content, we will always return spoofed userAgent and
+  // ignore the User-Agent header from the document channel when
+  // 'privacy.resistFingerprinting' is true.
+  if (!aWindow ||
+      (nsContentUtils::ShouldResistFingerprinting() && !aIsCallerChrome)) {
     return NS_OK;
   }
 
   // Copy the User-Agent header from the document channel which has already been
   // subject to UA overrides.
   nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
   if (!doc) {
     return NS_OK;
--- a/dom/workers/WorkerNavigator.cpp
+++ b/dom/workers/WorkerNavigator.cpp
@@ -8,16 +8,17 @@
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseWorkerProxy.h"
 #include "mozilla/dom/StorageManager.h"
 #include "mozilla/dom/WorkerNavigator.h"
 #include "mozilla/dom/WorkerNavigatorBinding.h"
 #include "mozilla/dom/network/Connection.h"
 
 #include "nsProxyRelease.h"
+#include "nsRFPService.h"
 #include "RuntimeService.h"
 
 #include "nsIDocument.h"
 
 #include "WorkerPrivate.h"
 #include "WorkerRunnable.h"
 #include "WorkerScope.h"
 
@@ -74,49 +75,61 @@ WorkerNavigator::SetLanguages(const nsTA
 }
 
 void
 WorkerNavigator::GetAppName(nsString& aAppName, CallerType aCallerType) const
 {
   WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
   MOZ_ASSERT(workerPrivate);
 
-  if (!mProperties.mAppNameOverridden.IsEmpty() &&
+  if ((!mProperties.mAppNameOverridden.IsEmpty() ||
+       workerPrivate->ResistFingerprintingEnabled()) &&
       !workerPrivate->UsesSystemPrincipal()) {
-    aAppName = mProperties.mAppNameOverridden;
+    // We will spoof this value when 'privacy.resistFingerprinting' is true.
+    // See nsRFPService.h for spoofed value.
+    aAppName = workerPrivate->ResistFingerprintingEnabled() ?
+      NS_LITERAL_STRING(SPOOFED_APPNAME) : mProperties.mAppNameOverridden;
   } else {
     aAppName = mProperties.mAppName;
   }
 }
 
 void
 WorkerNavigator::GetAppVersion(nsString& aAppVersion, CallerType aCallerType,
                                ErrorResult& aRv) const
 {
   WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
   MOZ_ASSERT(workerPrivate);
 
-  if (!mProperties.mAppVersionOverridden.IsEmpty() &&
+  if ((!mProperties.mAppVersionOverridden.IsEmpty() ||
+       workerPrivate->ResistFingerprintingEnabled()) &&
       !workerPrivate->UsesSystemPrincipal()) {
-    aAppVersion = mProperties.mAppVersionOverridden;
+    // We will spoof this value when 'privacy.resistFingerprinting' is true.
+    // See nsRFPService.h for spoofed value.
+    aAppVersion = workerPrivate->ResistFingerprintingEnabled() ?
+      NS_LITERAL_STRING(SPOOFED_APPVERSION) : mProperties.mAppVersionOverridden;
   } else {
     aAppVersion = mProperties.mAppVersion;
   }
 }
 
 void
 WorkerNavigator::GetPlatform(nsString& aPlatform, CallerType aCallerType,
                              ErrorResult& aRv) const
 {
   WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
   MOZ_ASSERT(workerPrivate);
 
-  if (!mProperties.mPlatformOverridden.IsEmpty() &&
+  if ((!mProperties.mPlatformOverridden.IsEmpty() ||
+       workerPrivate->ResistFingerprintingEnabled()) &&
       !workerPrivate->UsesSystemPrincipal()) {
-    aPlatform = mProperties.mPlatformOverridden;
+    // We will spoof this value when 'privacy.resistFingerprinting' is true.
+    // See nsRFPService.h for spoofed value.
+    aPlatform = workerPrivate->ResistFingerprintingEnabled() ?
+      NS_LITERAL_STRING(SPOOFED_PLATFORM) : mProperties.mPlatformOverridden;
   } else {
     aPlatform = mProperties.mPlatform;
   }
 }
 
 namespace {
 
 class GetUserAgentRunnable final : public WorkerMainThreadRunnable
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -51,16 +51,17 @@
 #include "nsHttpChannelAuthProvider.h"
 #include "nsServiceManagerUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsSocketTransportService2.h"
 #include "nsIOService.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIXULRuntime.h"
 #include "nsCharSeparatedTokenizer.h"
+#include "nsRFPService.h"
 
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/net/NeckoParent.h"
 #include "mozilla/ipc/URIUtils.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/Unused.h"
 #include "mozilla/BasePrincipal.h"
 
@@ -438,18 +439,18 @@ nsHttpHandler::Init()
 
     // Generating the spoofed userAgent for fingerprinting resistance. We will
     // round the version to the nearest 10. By doing so, the anonymity group will
     // cover more versions instead of one version.
     uint32_t spoofedVersion = mAppVersion.ToInteger(&rv);
     if (NS_SUCCEEDED(rv)) {
         spoofedVersion = spoofedVersion - (spoofedVersion % 10);
         mSpoofedUserAgent.Assign(nsPrintfCString(
-            "Mozilla/5.0 (Windows NT 6.1; rv:%d.0) Gecko/20100101 Firefox/%d.0",
-            spoofedVersion, spoofedVersion));
+            "Mozilla/5.0 (%s; rv:%d.0) Gecko/%s Firefox/%d.0",
+            SPOOFED_OSCPU, spoofedVersion, LEGACY_BUILD_ID, spoofedVersion));
     }
 
     mSessionStartTime = NowInSeconds();
     mHandlerActive = true;
 
     rv = mAuthCache.Init();
     if (NS_FAILED(rv)) return rv;
 
@@ -460,17 +461,17 @@ nsHttpHandler::Init()
     if (NS_FAILED(rv)) return rv;
 
     mRequestContextService =
         do_GetService("@mozilla.org/network/request-context-service;1");
 
 #if defined(ANDROID) || defined(MOZ_MULET)
     mProductSub.AssignLiteral(MOZILLA_UAVERSION);
 #else
-    mProductSub.AssignLiteral("20100101");
+    mProductSub.AssignLiteral(LEGACY_BUILD_ID);
 #endif
 
 #if DEBUG
     // dump user agent prefs
     LOG(("> legacy-app-name = %s\n", mLegacyAppName.get()));
     LOG(("> legacy-app-version = %s\n", mLegacyAppVersion.get()));
     LOG(("> platform = %s\n", mPlatform.get()));
     LOG(("> oscpu = %s\n", mOscpu.get()));
--- a/toolkit/components/resistfingerprinting/nsRFPService.h
+++ b/toolkit/components/resistfingerprinting/nsRFPService.h
@@ -6,16 +6,25 @@
 #ifndef __nsRFPService_h__
 #define __nsRFPService_h__
 
 #include "mozilla/Atomics.h"
 #include "nsIObserver.h"
 
 #include "nsString.h"
 
+// Defines regarding spoofed values of Navigator object. These spoofed values
+// are returned when 'privacy.resistFingerprinting' is true.
+#define SPOOFED_APPNAME    "Netscape"
+#define SPOOFED_APPVERSION "5.0 (Windows)"
+#define SPOOFED_OSCPU      "Windows NT 6.1"
+#define SPOOFED_PLATFORM   "Win32"
+
+#define LEGACY_BUILD_ID    "20100101"
+
 namespace mozilla {
 
 class nsRFPService final : public nsIObserver
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER