commit 62d76b2381c1df0b893336f496ae4ffe161d592f Author: Kathy Brade brade@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.