commit 62d76b2381c1df0b893336f496ae4ffe161d592f
Author: Kathy Brade <brade(a)pearlcrescent.com>
Date: Fri Sep 14 10:02:17 2018 -0400
Bug 26146: Spoof HTTP User-Agent header for desktop platforms
In Tor Browser 8.0, the OS was revealed in both the HTTP User-Agent
header and to JavaScript code via navigator.userAgent. To avoid
leaking the OS inside each HTTP request (which many web servers
log), always use the Windows 7 OS value in the desktop User-Agent
header. We continue to allow access to the actual OS via JavaScript,
since doing so improves compatibility with web applications such
as GitHub and Google Docs.
---
browser/app/profile/000-tor-browser.js | 1 -
dom/base/Navigator.cpp | 13 +++++++++++++
netwerk/protocol/http/nsHttpHandler.cpp | 2 +-
toolkit/components/resistfingerprinting/nsRFPService.cpp | 5 +++--
toolkit/components/resistfingerprinting/nsRFPService.h | 10 +++++++++-
5 files changed, 26 insertions(+), 5 deletions(-)
diff --git a/browser/app/profile/000-tor-browser.js b/browser/app/profile/000-tor-browser.js
index d9e609a71eb8..7b602c13e0d5 100644
--- a/browser/app/profile/000-tor-browser.js
+++ b/browser/app/profile/000-tor-browser.js
@@ -122,7 +122,6 @@ pref("general.appname.override", "Netscape");
pref("general.appversion.override", "5.0 (Windows)");
pref("general.oscpu.override", "Windows NT 6.1");
pref("general.platform.override", "Win32");
-pref("general.useragent.override", "Mozilla/5.0 (Windows NT 6.1; rv:60.0) Gecko/20100101 Firefox/60.0");
pref("general.productSub.override", "20100101");
pref("general.buildID.override", "20100101");
pref("browser.startup.homepage_override.buildID", "20100101");
diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp
index c2ec1f7081a3..33563ad65ccb 100644
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1772,6 +1772,19 @@ Navigator::GetUserAgent(nsPIDOMWindowInner* aWindow,
}
}
+ // When the caller is content and 'privacy.resistFingerprinting' is true,
+ // return a spoofed userAgent which reveals the platform but not the
+ // specific OS version, etc.
+ if (!aIsCallerChrome && nsContentUtils::ShouldResistFingerprinting()) {
+ nsAutoCString spoofedUA;
+ nsresult rv = nsRFPService::GetSpoofedUserAgent(spoofedUA, false);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ CopyASCIItoUTF16(spoofedUA, aUserAgent);
+ return NS_OK;
+ }
+
nsresult rv;
nsCOMPtr<nsIHttpProtocolHandler>
service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp
index f7f449868711..18f942c216fb 100644
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -491,7 +491,7 @@ nsHttpHandler::Init()
}
// Generating the spoofed User Agent for fingerprinting resistance.
- rv = nsRFPService::GetSpoofedUserAgent(mSpoofedUserAgent);
+ rv = nsRFPService::GetSpoofedUserAgent(mSpoofedUserAgent, true);
if (NS_FAILED(rv)) {
// Empty mSpoofedUserAgent to make sure the unsuccessful spoofed UA string
// will not be used anywhere.
diff --git a/toolkit/components/resistfingerprinting/nsRFPService.cpp b/toolkit/components/resistfingerprinting/nsRFPService.cpp
index f560ce27f228..595e6556a27e 100644
--- a/toolkit/components/resistfingerprinting/nsRFPService.cpp
+++ b/toolkit/components/resistfingerprinting/nsRFPService.cpp
@@ -666,7 +666,7 @@ nsRFPService::GetSpoofedPresentedFrames(double aTime, uint32_t aWidth, uint32_t
/* static */
nsresult
-nsRFPService::GetSpoofedUserAgent(nsACString &userAgent)
+nsRFPService::GetSpoofedUserAgent(nsACString &userAgent, bool isForHTTPHeader)
{
// This function generates the spoofed value of User Agent.
// We spoof the values of the platform and Firefox version, which could be
@@ -703,9 +703,10 @@ nsRFPService::GetSpoofedUserAgent(nsACString &userAgent)
// Except we used 60 as an ESR instead of 59.
// We infer the last and closest ESR version based on this rule.
uint32_t spoofedVersion = firefoxVersion - ((firefoxVersion - 4) % 7);
+ const char *spoofedOS = isForHTTPHeader ? SPOOFED_HTTP_UA_OS : SPOOFED_UA_OS;
userAgent.Assign(nsPrintfCString(
"Mozilla/5.0 (%s; rv:%d.0) Gecko/%s Firefox/%d.0",
- SPOOFED_UA_OS, spoofedVersion, LEGACY_BUILD_ID, spoofedVersion));
+ spoofedOS, spoofedVersion, LEGACY_BUILD_ID, spoofedVersion));
return rv;
}
diff --git a/toolkit/components/resistfingerprinting/nsRFPService.h b/toolkit/components/resistfingerprinting/nsRFPService.h
index 9708d362496f..da79da8de948 100644
--- a/toolkit/components/resistfingerprinting/nsRFPService.h
+++ b/toolkit/components/resistfingerprinting/nsRFPService.h
@@ -48,6 +48,14 @@
#define SPOOFED_APPNAME "Netscape"
#define LEGACY_BUILD_ID "20100101"
+// For the HTTP User-Agent header, we use a simpler set of spoofed values
+// that do not reveal the specific desktop platform.
+#if defined(MOZ_WIDGET_ANDROID)
+#define SPOOFED_HTTP_UA_OS "Android 6.0; Mobile"
+#else
+#define SPOOFED_HTTP_UA_OS "Windows NT 6.1"
+#endif
+
// Forward declare LRUCache, defined in nsRFPService.cpp
class LRUCache;
@@ -212,7 +220,7 @@ public:
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);
+ static nsresult GetSpoofedUserAgent(nsACString &userAgent, bool isForHTTPHeader);
/**
* This method for getting spoofed modifier states for the given keyboard event.