Bug 1393283 - Use the last ESR version as the spoofed Firefox version. r=tihuang, r=mcmanus
authorEthan <ettseng@mozilla.com>
Fri, 01 Sep 2017 17:29:44 +0800
changeset 379120 52937159a1b67176c18f62861e885a9f8d031f05
parent 379119 f56376db333bb81776048002c27b60912fac593f
child 379121 dadf26985c95d88cb187a26ec619a4898089a0c4
push id32449
push userarchaeopteryx@coole-files.de
push dateWed, 06 Sep 2017 09:33:20 +0000
treeherdermozilla-central@c959327c6b75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstihuang, mcmanus
bugs1393283
milestone57.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 1393283 - Use the last ESR version as the spoofed Firefox version. r=tihuang, r=mcmanus
browser/components/resistfingerprinting/test/browser/browser_navigator.js
netwerk/protocol/http/nsHttpHandler.cpp
toolkit/components/resistfingerprinting/nsRFPService.cpp
toolkit/components/resistfingerprinting/nsRFPService.h
--- a/browser/components/resistfingerprinting/test/browser/browser_navigator.js
+++ b/browser/components/resistfingerprinting/test/browser/browser_navigator.js
@@ -86,17 +86,17 @@ async function testWorkerNavigator() {
 
 add_task(async function setup() {
   await SpecialPowers.pushPrefEnv({"set":
     [["privacy.resistFingerprinting", true]]
   });
 
   let appInfo = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
   let appVersion = parseInt(appInfo.version);
-  let spoofedVersion = appVersion - (appVersion % 10);
+  let spoofedVersion = appVersion - ((appVersion - 3) % 7);
   spoofedUserAgent = `Mozilla/5.0 (Windows NT 6.1; rv:${spoofedVersion}.0) Gecko/20100101 Firefox/${spoofedVersion}.0`;
 });
 
 add_task(async function runNavigatorTest() {
   await testNavigator();
 });
 
 add_task(async function runWorkerNavigatorTest() {
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -456,26 +456,22 @@ nsHttpHandler::Init()
           appInfo->GetName(mAppName);
         }
         appInfo->GetVersion(mAppVersion);
         mAppName.StripChars(R"( ()<>@,;:\"/[]?={})");
     } else {
         mAppVersion.AssignLiteral(MOZ_APP_UA_VERSION);
     }
 
-    // Generating the spoofed userAgent for fingerprinting resistance.
-    // The browser version will be rounded down to a multiple of 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 (%s; rv:%d.0) Gecko/%s Firefox/%d.0",
-            SPOOFED_OSCPU, spoofedVersion, LEGACY_BUILD_ID, spoofedVersion));
+    // Generating the spoofed User Agent for fingerprinting resistance.
+    rv = nsRFPService::GetSpoofedUserAgent(mSpoofedUserAgent);
+    if (NS_FAILED(rv)) {
+      // Empty mSpoofedUserAgent to make sure the unsuccessful spoofed UA string
+      // will not be used anywhere.
+      mSpoofedUserAgent.Truncate();
     }
 
     mSessionStartTime = NowInSeconds();
     mHandlerActive = true;
 
     rv = mAuthCache.Init();
     if (NS_FAILED(rv)) return rv;
 
--- a/toolkit/components/resistfingerprinting/nsRFPService.cpp
+++ b/toolkit/components/resistfingerprinting/nsRFPService.cpp
@@ -13,20 +13,23 @@
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 
 #include "nsCOMPtr.h"
 #include "nsCoord.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 #include "nsXULAppAPI.h"
+#include "nsPrintfCString.h"
 
 #include "nsIObserverService.h"
 #include "nsIPrefBranch.h"
 #include "nsIPrefService.h"
+#include "nsIXULAppInfo.h"
+#include "nsIXULRuntime.h"
 #include "nsJSUtils.h"
 
 #include "prenv.h"
 
 #include "js/Date.h"
 
 using namespace mozilla;
 using namespace std;
@@ -157,16 +160,69 @@ nsRFPService::GetSpoofedPresentedFrames(
 
   double time = ReduceTimePrecisionAsSecs(aTime);
   // Bound the dropped ratio from 0 to 100.
   uint32_t boundedDroppedRatio = min(sVideoDroppedRatio, 100u);
 
   return NSToIntFloor(time * sVideoFramesPerSec * ((100 - boundedDroppedRatio) / 100.0));
 }
 
+/* static */
+nsresult
+nsRFPService::GetSpoofedUserAgent(nsACString &userAgent)
+{
+  // This function generates the spoofed value of User Agent.
+  // We spoof the values of the platform and Firefox version, which could be
+  // used as fingerprinting sources to identify individuals.
+  // Reference of the format of User Agent:
+  // https://developer.mozilla.org/en-US/docs/Web/API/NavigatorID/userAgent
+  // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent
+
+  nsresult rv;
+  nsCOMPtr<nsIXULAppInfo> appInfo =
+    do_GetService("@mozilla.org/xre/app-info;1", &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsAutoCString appVersion;
+  rv = appInfo->GetVersion(appVersion);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // The browser version will be spoofed as the last ESR version.
+  // By doing so, the anonymity group will cover more versions instead of one
+  // version.
+  uint32_t firefoxVersion = appVersion.ToInteger(&rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Starting from Firefox 10, Firefox ESR was released once every seven
+  // Firefox releases, e.g. Firefox 10, 17, 24, 31, and so on.
+  // We infer the last and closest ESR version based on this rule.
+  nsCOMPtr<nsIXULRuntime> runtime =
+    do_GetService("@mozilla.org/xre/runtime;1", &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsAutoCString updateChannel;
+  rv = runtime->GetDefaultUpdateChannel(updateChannel);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // If we are running in Firefox ESR, determine whether the formula of ESR
+  // version has changed.  Once changed, we must update the formula in this
+  // function.
+  if (updateChannel.Equals("esr")) {
+    MOZ_ASSERT(((firefoxVersion % 7) == 3),
+      "Please udpate ESR version formula in nsRFPService.cpp");
+  }
+
+  uint32_t spoofedVersion = firefoxVersion - ((firefoxVersion - 3) % 7);
+  userAgent.Assign(nsPrintfCString(
+    "Mozilla/5.0 (%s; rv:%d.0) Gecko/%s Firefox/%d.0",
+    SPOOFED_OSCPU, spoofedVersion, LEGACY_BUILD_ID, spoofedVersion));
+
+  return rv;
+}
+
 nsresult
 nsRFPService::Init()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsresult rv;
 
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
--- a/toolkit/components/resistfingerprinting/nsRFPService.h
+++ b/toolkit/components/resistfingerprinting/nsRFPService.h
@@ -44,16 +44,19 @@ public:
   static uint32_t CalculateTargetVideoResolution(uint32_t aVideoQuality);
 
   // Methods for getting spoofed media statistics and the return value will
   // depend on the video resolution.
   static uint32_t GetSpoofedTotalFrames(double aTime);
   static uint32_t GetSpoofedDroppedFrames(double aTime, uint32_t aWidth, uint32_t aHeight);
   static uint32_t GetSpoofedPresentedFrames(double aTime, uint32_t aWidth, uint32_t aHeight);
 
+  // This method generates the spoofed value of User Agent.
+  static nsresult GetSpoofedUserAgent(nsACString &userAgent);
+
 private:
   nsresult Init();
 
   nsRFPService() {}
 
   ~nsRFPService() {}
 
   void UpdatePref();