-
Notifications
You must be signed in to change notification settings - Fork 888
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement navigator.userAgent farbling
. . . . . . . . . . . . fix unused function error on Linux break out build, always set UA, test farbling reset build things more deps less nesting no nesting don't run on DidRedirectNavigation, explicitly set ua override to false if we're not overriding max UA should be suffixed off default UA, not upstream UA
- Loading branch information
1 parent
39b61ba
commit 76bd866
Showing
10 changed files
with
471 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
source_set("farbling") { | ||
check_includes = false | ||
sources = [ | ||
"farbling_tab_helper.cc", | ||
"farbling_tab_helper.h", | ||
] | ||
|
||
deps = [ | ||
"//base", | ||
"//brave/components/brave_shields/browser:browser", | ||
"//components/version_info", | ||
"//content/public/browser", | ||
"//content/public/common", | ||
"//chrome/common", | ||
"//net", | ||
"//third_party/blink/public/common", | ||
] | ||
} |
161 changes: 161 additions & 0 deletions
161
browser/farbling/brave_navigator_useragent_farbling_browsertest.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
/* Copyright (c) 2020 The Brave Authors. All rights reserved. | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this file, | ||
* You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
#include "base/path_service.h" | ||
#include "base/strings/stringprintf.h" | ||
#include "base/task/post_task.h" | ||
#include "base/test/thread_test_helper.h" | ||
#include "brave/browser/brave_browser_process_impl.h" | ||
#include "brave/browser/brave_content_browser_client.h" | ||
#include "brave/browser/extensions/brave_base_local_data_files_browsertest.h" | ||
#include "brave/common/brave_paths.h" | ||
#include "brave/common/pref_names.h" | ||
#include "brave/components/brave_component_updater/browser/local_data_files_service.h" | ||
#include "brave/components/brave_shields/browser/brave_shields_util.h" | ||
#include "chrome/browser/content_settings/host_content_settings_map_factory.h" | ||
#include "chrome/browser/extensions/extension_browsertest.h" | ||
#include "chrome/browser/ui/browser.h" | ||
#include "chrome/common/chrome_content_client.h" | ||
#include "chrome/test/base/in_process_browser_test.h" | ||
#include "chrome/test/base/ui_test_utils.h" | ||
#include "components/permissions/permission_request.h" | ||
#include "components/prefs/pref_service.h" | ||
#include "content/public/browser/render_frame_host.h" | ||
#include "content/public/test/browser_test.h" | ||
#include "content/public/test/browser_test_utils.h" | ||
#include "net/dns/mock_host_resolver.h" | ||
|
||
using brave_shields::ControlType; | ||
|
||
const char kUserAgentScript[] = | ||
"domAutomationController.send(navigator.userAgent);"; | ||
|
||
class BraveNavigatorUserAgentFarblingBrowserTest : public InProcessBrowserTest { | ||
public: | ||
void SetUpOnMainThread() override { | ||
InProcessBrowserTest::SetUpOnMainThread(); | ||
|
||
content_client_.reset(new ChromeContentClient); | ||
content::SetContentClient(content_client_.get()); | ||
browser_content_client_.reset(new BraveContentBrowserClient()); | ||
content::SetBrowserClientForTesting(browser_content_client_.get()); | ||
|
||
host_resolver()->AddRule("*", "127.0.0.1"); | ||
content::SetupCrossSiteRedirector(embedded_test_server()); | ||
|
||
brave::RegisterPathProvider(); | ||
base::FilePath test_data_dir; | ||
base::PathService::Get(brave::DIR_TEST_DATA, &test_data_dir); | ||
embedded_test_server()->ServeFilesFromDirectory(test_data_dir); | ||
|
||
ASSERT_TRUE(embedded_test_server()->Start()); | ||
} | ||
|
||
void TearDown() override { | ||
browser_content_client_.reset(); | ||
content_client_.reset(); | ||
} | ||
|
||
HostContentSettingsMap* content_settings() { | ||
return HostContentSettingsMapFactory::GetForProfile(browser()->profile()); | ||
} | ||
|
||
void AllowFingerprinting(std::string domain) { | ||
brave_shields::SetFingerprintingControlType( | ||
content_settings(), ControlType::ALLOW, | ||
embedded_test_server()->GetURL(domain, "/")); | ||
} | ||
|
||
void BlockFingerprinting(std::string domain) { | ||
brave_shields::SetFingerprintingControlType( | ||
content_settings(), ControlType::BLOCK, | ||
embedded_test_server()->GetURL(domain, "/")); | ||
} | ||
|
||
void SetFingerprintingDefault(std::string domain) { | ||
brave_shields::SetFingerprintingControlType( | ||
content_settings(), ControlType::DEFAULT, | ||
embedded_test_server()->GetURL(domain, "/")); | ||
} | ||
|
||
template <typename T> | ||
int ExecScriptGetInt(const std::string& script, T* frame) { | ||
int value; | ||
EXPECT_TRUE(ExecuteScriptAndExtractInt(frame, script, &value)); | ||
return value; | ||
} | ||
|
||
template <typename T> | ||
std::string ExecScriptGetStr(const std::string& script, T* frame) { | ||
std::string value; | ||
EXPECT_TRUE(ExecuteScriptAndExtractString(frame, script, &value)); | ||
return value; | ||
} | ||
|
||
content::WebContents* contents() { | ||
return browser()->tab_strip_model()->GetActiveWebContents(); | ||
} | ||
|
||
bool NavigateToURLUntilLoadStop(const GURL& url) { | ||
ui_test_utils::NavigateToURL(browser(), url); | ||
return WaitForLoadStop(contents()); | ||
} | ||
|
||
private: | ||
std::unique_ptr<ChromeContentClient> content_client_; | ||
std::unique_ptr<BraveContentBrowserClient> browser_content_client_; | ||
}; | ||
|
||
// Tests results of farbling user agent | ||
IN_PROC_BROWSER_TEST_F(BraveNavigatorUserAgentFarblingBrowserTest, | ||
FarbleNavigatorUserAgent) { | ||
std::string domain_b = "b.com"; | ||
std::string domain_z = "z.com"; | ||
GURL url_b = embedded_test_server()->GetURL(domain_b, "/simple.html"); | ||
GURL url_z = embedded_test_server()->GetURL(domain_z, "/simple.html"); | ||
|
||
// Farbling level: off | ||
// get real navigator.userAgent | ||
AllowFingerprinting(domain_b); | ||
NavigateToURLUntilLoadStop(url_b); | ||
std::string off_ua_b = ExecScriptGetStr(kUserAgentScript, contents()); | ||
AllowFingerprinting(domain_z); | ||
NavigateToURLUntilLoadStop(url_z); | ||
std::string off_ua_z = ExecScriptGetStr(kUserAgentScript, contents()); | ||
// user agent should be the same on every domain if farbling is off | ||
EXPECT_EQ(off_ua_b, off_ua_z); | ||
|
||
// Farbling level: default | ||
// navigator.userAgent may be farbled, but the farbling is not | ||
// domain-specific | ||
SetFingerprintingDefault(domain_b); | ||
NavigateToURLUntilLoadStop(url_b); | ||
std::string default_ua_b = ExecScriptGetStr(kUserAgentScript, contents()); | ||
SetFingerprintingDefault(domain_z); | ||
NavigateToURLUntilLoadStop(url_z); | ||
std::string default_ua_z = ExecScriptGetStr(kUserAgentScript, contents()); | ||
// user agent should be the same on every domain if farbling is default | ||
EXPECT_EQ(default_ua_b, default_ua_z); | ||
|
||
// Farbling level: maximum | ||
// navigator.userAgent should be the possibly-farbled string from the default | ||
// farbling level, further suffixed by a pseudo-random number of spaces based | ||
// on domain and session key | ||
BlockFingerprinting(domain_b); | ||
NavigateToURLUntilLoadStop(url_b); | ||
std::string max_ua_b = ExecScriptGetStr(kUserAgentScript, contents()); | ||
EXPECT_EQ(max_ua_b, default_ua_b + " "); | ||
BlockFingerprinting(domain_z); | ||
NavigateToURLUntilLoadStop(url_z); | ||
std::string max_ua_z = ExecScriptGetStr(kUserAgentScript, contents()); | ||
EXPECT_EQ(max_ua_z, default_ua_z + " "); | ||
|
||
// Farbling level: off | ||
// verify that user agent is reset properly after having been farbled | ||
AllowFingerprinting(domain_b); | ||
NavigateToURLUntilLoadStop(url_b); | ||
std::string off_ua_b2 = ExecScriptGetStr(kUserAgentScript, contents()); | ||
EXPECT_EQ(off_ua_b, off_ua_b2); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
/* Copyright (c) 2020 The Brave Authors. All rights reserved. | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this file, | ||
* You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
#include "brave/browser/farbling/farbling_tab_helper.h" | ||
|
||
#include <algorithm> | ||
#include <string> | ||
|
||
#include "base/system/sys_info.h" | ||
#include "brave/components/brave_shields/browser/brave_shields_util.h" | ||
#include "chrome/browser/chrome_content_browser_client.h" | ||
#include "chrome/browser/content_settings/host_content_settings_map_factory.h" | ||
#include "chrome/browser/profiles/profile.h" | ||
#include "components/version_info/version_info.h" | ||
#include "content/public/browser/navigation_handle.h" | ||
#include "content/public/common/content_client.h" | ||
#include "content/public/common/user_agent.h" | ||
#include "net/http/http_util.h" | ||
#include "third_party/blink/public/common/features.h" | ||
#include "third_party/blink/public/common/user_agent/user_agent_metadata.h" | ||
|
||
using brave_shields::ControlType; | ||
using brave_shields::GetBraveShieldsEnabled; | ||
using brave_shields::GetFingerprintingControlType; | ||
|
||
namespace { | ||
|
||
#if defined(OS_MACOSX) | ||
int32_t GetMinimumBugfixVersion(int32_t os_major_version, | ||
int32_t os_minor_version) { | ||
if (os_major_version == 10) { | ||
switch (os_minor_version) { | ||
case 9: | ||
case 10: | ||
return 5; | ||
case 11: | ||
case 12: | ||
case 13: | ||
case 14: | ||
case 15: | ||
return 6; | ||
} | ||
} | ||
return 0; | ||
} | ||
#endif | ||
|
||
std::string GetUserAgentPlatform() { | ||
#if defined(OS_WIN) | ||
return ""; | ||
#elif defined(OS_MACOSX) | ||
return "Macintosh; "; | ||
#elif defined(USE_X11) | ||
return "X11; "; | ||
#elif defined(OS_ANDROID) | ||
return "Linux; "; | ||
#elif defined(OS_POSIX) | ||
return "Unknown; "; | ||
#endif | ||
} | ||
|
||
std::string GetMinimalProduct() { | ||
return version_info::GetProductNameAndVersionForUserAgent(); | ||
} | ||
|
||
std::string GetMinimalOSVersion() { | ||
std::string os_version; | ||
#if defined(OS_WIN) || defined(OS_MACOSX) | ||
int32_t os_major_version = 0; | ||
int32_t os_minor_version = 0; | ||
int32_t os_bugfix_version = 0; | ||
base::SysInfo::OperatingSystemVersionNumbers( | ||
&os_major_version, &os_minor_version, &os_bugfix_version); | ||
#endif | ||
#if defined(OS_MACOSX) | ||
os_bugfix_version = | ||
std::max(os_bugfix_version, | ||
GetMinimumBugfixVersion(os_major_version, os_minor_version)); | ||
#endif | ||
|
||
#if defined(OS_ANDROID) | ||
std::string android_version_str = base::SysInfo::OperatingSystemVersion(); | ||
std::string android_info_str = | ||
GetAndroidOSInfo(content::IncludeAndroidBuildNumber::Exclude, | ||
content::IncludeAndroidModel::Exclude); | ||
#endif | ||
|
||
base::StringAppendF(&os_version, | ||
#if defined(OS_WIN) | ||
"%d.%d", os_major_version, os_minor_version | ||
#elif defined(OS_MACOSX) | ||
"%d_%d_%d", os_major_version, os_minor_version, | ||
os_bugfix_version | ||
#elif defined(OS_ANDROID) | ||
"%s%s", android_version_str.c_str(), | ||
android_info_str.c_str() | ||
#else | ||
"" | ||
#endif | ||
); // NOLINT | ||
return os_version; | ||
} | ||
|
||
} // namespace | ||
|
||
namespace brave { | ||
|
||
FarblingTabHelper::~FarblingTabHelper() = default; | ||
|
||
FarblingTabHelper::FarblingTabHelper(content::WebContents* web_contents) | ||
: content::WebContentsObserver(web_contents) {} | ||
|
||
void FarblingTabHelper::DidStartNavigation( | ||
content::NavigationHandle* navigation_handle) { | ||
UpdateUserAgent(navigation_handle); | ||
} | ||
|
||
void FarblingTabHelper::UpdateUserAgent( | ||
content::NavigationHandle* navigation_handle) { | ||
if (!navigation_handle) | ||
return; | ||
content::WebContents* web_contents = navigation_handle->GetWebContents(); | ||
if (!web_contents) | ||
return; | ||
std::string ua = ""; | ||
Profile* profile = static_cast<Profile*>(web_contents->GetBrowserContext()); | ||
auto* map = HostContentSettingsMapFactory::GetForProfile(profile); | ||
// If shields is off or farbling is off, do not override. | ||
// Also, we construct real user agent two different ways, through the browser | ||
// client's higher level utility function and through direct functions. If | ||
// they differ, there's some sort of override happening. Maybe the end | ||
// user is forcing the user agent via command line flags. Or maybe they | ||
// turned on the "freeze user agent" flag. Whatever it is, we want to | ||
// respect it. | ||
if (GetBraveShieldsEnabled(map, navigation_handle->GetURL()) && | ||
(GetFingerprintingControlType(map, navigation_handle->GetURL()) != | ||
ControlType::ALLOW) && | ||
(GetUserAgent() == | ||
content::BuildUserAgentFromProduct( | ||
version_info::GetProductNameAndVersionForUserAgent()))) { | ||
std::string minimal_os_info; | ||
base::StringAppendF(&minimal_os_info, "%s%s", | ||
GetUserAgentPlatform().c_str(), | ||
content::BuildOSCpuInfoFromOSVersionAndCpuType( | ||
GetMinimalOSVersion(), content::BuildCpuInfo()) | ||
.c_str()); | ||
ua = content::BuildUserAgentFromOSAndProduct(minimal_os_info, | ||
GetMinimalProduct()); | ||
navigation_handle->SetIsOverridingUserAgent(true); | ||
web_contents->SetUserAgentOverride( | ||
blink::UserAgentOverride::UserAgentOnly(ua), | ||
false /* override_in_new_tabs */); | ||
} else { | ||
navigation_handle->SetIsOverridingUserAgent(false); | ||
} | ||
} | ||
|
||
WEB_CONTENTS_USER_DATA_KEY_IMPL(FarblingTabHelper) | ||
|
||
} // namespace brave |
Oops, something went wrong.