Bug 1404608 - Reveal the real operating system when fingerprinting resistance is enabled. r=arthuredelstein,smaug
authorTim Huang <tihuang@mozilla.com>
Tue, 12 Dec 2017 15:25:49 -0600
changeset 398586 9c586454144b4eef9e9a8ab53e3d1a8c3f84ac3c
parent 398585 731b1321ba9566f571aed01387bf34a66390d86f
child 398587 9b49df8dc9b9ba12db1f83e875df529394b26a36
push id33224
push userdluca@mozilla.com
push dateWed, 10 Jan 2018 21:59:28 +0000
treeherdermozilla-central@57386b58c057 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersarthuredelstein, smaug
bugs1404608
milestone59.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 1404608 - Reveal the real operating system when fingerprinting resistance is enabled. r=arthuredelstein,smaug This patch makes Firefox not to lie about the real operating system when pref 'privacy.resistFingerprinting' is true. This will also change the testcase as well. MozReview-Commit-ID: Gdnp2lMU3wr
browser/components/resistfingerprinting/test/browser/browser_navigator.js
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
@@ -1,24 +1,53 @@
 /**
  * Bug 1333651 - A test case for making sure the navigator object has been
  *   spoofed/disabled correctly.
  */
 
 const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
 
+XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
+  "resource://gre/modules/AppConstants.jsm");
+
 const TEST_PATH = "http://example.net/browser/browser/" +
                   "components/resistfingerprinting/test/browser/";
 
 var spoofedUserAgent;
 
-const SPOOFED_APPNAME        = "Netscape";
-const SPOOFED_APPVERSION     = "5.0 (Windows)";
-const SPOOFED_PLATFORM       = "Win64";
-const SPOOFED_OSCPU          = "Windows NT 6.1; Win64; x64";
+const SPOOFED_APPNAME = "Netscape";
+
+const SPOOFED_APPVERSION = {
+  linux: "5.0 (X11)",
+  win: "5.0 (Windows)",
+  macosx: "5.0 (Macintosh)",
+  android: "5.0 (Android 6.0)",
+  other: "5.0 (X11)",
+};
+const SPOOFED_PLATFORM = {
+  linux: "Linux x86_64",
+  win: "Win64",
+  macosx: "MacIntel",
+  android: "Linux armv7l",
+  other: "Linux x86_64",
+};
+const SPOOFED_OSCPU = {
+  linux: "Linux x86_64",
+  win: "Windows NT 6.1; Win64; x64",
+  macosx: "Intel Mac OS X 10.13",
+  android: "Linux armv7l",
+  other: "Linux x86_64",
+};
+const SPOOFED_UA_OS = {
+  linux: "X11; Linux x86_64",
+  win: "Windows NT 6.1; Win64; x64",
+  macosx: "Macintosh; Intel Mac OS X 10.13",
+  android: "Android 6.0; Mobile",
+  other: "X11; Linux x86_64",
+};
 const SPOOFED_BUILDID        = "20100101";
 const SPOOFED_HW_CONCURRENCY = 2;
 
 const CONST_APPCODENAME = "Mozilla";
 const CONST_PRODUCT     = "Gecko";
 const CONST_PRODUCTSUB  = "20100101";
 const CONST_VENDOR      = "";
 const CONST_VENDORSUB   = "";
@@ -30,22 +59,22 @@ async function testNavigator() {
 
   let result = await ContentTask.spawn(tab.linkedBrowser, null, function() {
     return content.document.getElementById("result").innerHTML;
   });
 
   result = JSON.parse(result);
 
   is(result.appName, SPOOFED_APPNAME, "Navigator.appName is correctly spoofed.");
-  is(result.appVersion, SPOOFED_APPVERSION, "Navigator.appVersion is correctly spoofed.");
-  is(result.platform, SPOOFED_PLATFORM, "Navigator.platform is correctly spoofed.");
+  is(result.appVersion, SPOOFED_APPVERSION[AppConstants.platform], "Navigator.appVersion is correctly spoofed.");
+  is(result.platform, SPOOFED_PLATFORM[AppConstants.platform], "Navigator.platform is correctly spoofed.");
   is(result.userAgent, spoofedUserAgent, "Navigator.userAgent is correctly spoofed.");
   is(result.mimeTypesLength, 0, "Navigator.mimeTypes has a length of 0.");
   is(result.pluginsLength, 0, "Navigator.plugins has a length of 0.");
-  is(result.oscpu, SPOOFED_OSCPU, "Navigator.oscpu is correctly spoofed.");
+  is(result.oscpu, SPOOFED_OSCPU[AppConstants.platform], "Navigator.oscpu is correctly spoofed.");
   is(result.buildID, SPOOFED_BUILDID, "Navigator.buildID is correctly spoofed.");
   is(result.hardwareConcurrency, SPOOFED_HW_CONCURRENCY, "Navigator.hardwareConcurrency is correctly spoofed.");
 
   is(result.appCodeName, CONST_APPCODENAME, "Navigator.appCodeName reports correct constant value.");
   is(result.product, CONST_PRODUCT, "Navigator.product reports correct constant value.");
   is(result.productSub, CONST_PRODUCTSUB, "Navigator.productSub reports correct constant value.");
   is(result.vendor, CONST_VENDOR, "Navigator.vendor reports correct constant value.");
   is(result.vendorSub, CONST_VENDORSUB, "Navigator.vendorSub reports correct constant value.");
@@ -68,35 +97,35 @@ async function testWorkerNavigator() {
     });
 
     return res;
   });
 
   result = JSON.parse(result);
 
   is(result.appName, SPOOFED_APPNAME, "Navigator.appName is correctly spoofed.");
-  is(result.appVersion, SPOOFED_APPVERSION, "Navigator.appVersion is correctly spoofed.");
-  is(result.platform, SPOOFED_PLATFORM, "Navigator.platform is correctly spoofed.");
+  is(result.appVersion, SPOOFED_APPVERSION[AppConstants.platform], "Navigator.appVersion is correctly spoofed.");
+  is(result.platform, SPOOFED_PLATFORM[AppConstants.platform], "Navigator.platform is correctly spoofed.");
   is(result.userAgent, spoofedUserAgent, "Navigator.userAgent is correctly spoofed.");
   is(result.hardwareConcurrency, SPOOFED_HW_CONCURRENCY, "Navigator.hardwareConcurrency is correctly spoofed.");
 
   is(result.appCodeName, CONST_APPCODENAME, "Navigator.appCodeName reports correct constant value.");
   is(result.product, CONST_PRODUCT, "Navigator.product reports correct constant value.");
 
   await BrowserTestUtils.removeTab(tab);
 }
 
 add_task(async function setup() {
   await SpecialPowers.pushPrefEnv({"set":
     [["privacy.resistFingerprinting", true]]
   });
 
   let appVersion = parseInt(Services.appinfo.version);
   let spoofedVersion = appVersion - ((appVersion - 3) % 7);
-  spoofedUserAgent = `Mozilla/5.0 (${SPOOFED_OSCPU}; rv:${spoofedVersion}.0) Gecko/20100101 Firefox/${spoofedVersion}.0`;
+  spoofedUserAgent = `Mozilla/5.0 (${SPOOFED_UA_OS[AppConstants.platform]}; rv:${spoofedVersion}.0) Gecko/20100101 Firefox/${spoofedVersion}.0`;
 });
 
 add_task(async function runNavigatorTest() {
   await testNavigator();
 });
 
 add_task(async function runWorkerNavigatorTest() {
   await testWorkerNavigator();
--- a/toolkit/components/resistfingerprinting/nsRFPService.cpp
+++ b/toolkit/components/resistfingerprinting/nsRFPService.cpp
@@ -208,17 +208,17 @@ nsRFPService::GetSpoofedUserAgent(nsACSt
   if (updateChannel.EqualsLiteral("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));
+    SPOOFED_UA_OS, spoofedVersion, LEGACY_BUILD_ID, spoofedVersion));
 
   return rv;
 }
 
 nsresult
 nsRFPService::Init()
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/toolkit/components/resistfingerprinting/nsRFPService.h
+++ b/toolkit/components/resistfingerprinting/nsRFPService.h
@@ -8,21 +8,45 @@
 
 #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"
+// We decided to give different spoofed values according to the platform. The
+// reason is that it is easy to detect the real platform. So there is no benefit
+// for hiding the platform: it only brings breakages, like keyboard shortcuts won't
+// work in MAC OS if we spoof it as a window platform.
+#ifdef XP_WIN
+#define SPOOFED_UA_OS      "Windows NT 6.1; Win64; x64"
 #define SPOOFED_APPVERSION "5.0 (Windows)"
 #define SPOOFED_OSCPU      "Windows NT 6.1; Win64; x64"
 #define SPOOFED_PLATFORM   "Win64"
+#elif defined(XP_MACOSX)
+#define SPOOFED_UA_OS      "Macintosh; Intel Mac OS X 10.13"
+#define SPOOFED_APPVERSION "5.0 (Macintosh)"
+#define SPOOFED_OSCPU      "Intel Mac OS X 10.13"
+#define SPOOFED_PLATFORM   "MacIntel"
+#elif defined(MOZ_WIDGET_ANDROID)
+#define SPOOFED_UA_OS      "Android 6.0; Mobile"
+#define SPOOFED_APPVERSION "5.0 (Android 6.0)"
+#define SPOOFED_OSCPU      "Linux armv7l"
+#define SPOOFED_PLATFORM   "Linux armv7l"
+#else
+// For Linux and other platforms, like BSDs, SunOS and etc, we will use Linux
+// platform.
+#define SPOOFED_UA_OS      "X11; Linux x86_64"
+#define SPOOFED_APPVERSION "5.0 (X11)"
+#define SPOOFED_OSCPU      "Linux x86_64"
+#define SPOOFED_PLATFORM   "Linux x86_64"
+#endif
 
+#define SPOOFED_APPNAME    "Netscape"
 #define LEGACY_BUILD_ID    "20100101"
 
 namespace mozilla {
 
 class nsRFPService final : public nsIObserver
 {
 public:
   NS_DECL_ISUPPORTS