diff --git a/browser/brave_content_browser_client.cc b/browser/brave_content_browser_client.cc index 86e10a979f7a..8dd9686192b4 100644 --- a/browser/brave_content_browser_client.cc +++ b/browser/brave_content_browser_client.cc @@ -295,12 +295,15 @@ void BraveContentBrowserClient::MaybeHideReferrer( GURL(), CONTENT_SETTINGS_TYPE_PLUGINS, brave_shields::kBraveShields); + + // Navigations get empty referrers (brave/brave-browser#3422). + const GURL empty_referrer_url; brave_shields::ShouldSetReferrer(allow_referrers, shields_up, referrer->url, document_url, request_url, - request_url.GetOrigin(), + empty_referrer_url, referrer->policy, referrer); } diff --git a/browser/brave_content_browser_client_browsertest.cc b/browser/brave_content_browser_client_browsertest.cc index f4b551478811..d5418cd9c541 100644 --- a/browser/brave_content_browser_client_browsertest.cc +++ b/browser/brave_content_browser_client_browsertest.cc @@ -478,15 +478,24 @@ IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientReferrerTest, content::Referrer kReferrer(kDocumentUrl, network::mojom::ReferrerPolicy::kDefault); - // Should be hidden by default. + // Cross-origin navigations don't get a referrer. content::Referrer referrer = kReferrer; client()->MaybeHideReferrer(browser()->profile(), kRequestUrl, kDocumentUrl, &referrer); - EXPECT_EQ(referrer.url, kRequestUrl.GetOrigin()); + EXPECT_EQ(referrer.url, GURL()); + + // Same-origin navigations get full referrers. + const GURL kSameOriginRequest("http://document.com/different/path"); + referrer = kReferrer; + client()->MaybeHideReferrer(browser()->profile(), + kSameOriginRequest, kDocumentUrl, + &referrer); + EXPECT_EQ(referrer.url, kDocumentUrl); // Special rule for extensions. const GURL kExtensionUrl("chrome-extension://abc/path?query"); + referrer = kReferrer; referrer.url = kExtensionUrl; client()->MaybeHideReferrer(browser()->profile(), kRequestUrl, kExtensionUrl, diff --git a/renderer/brave_content_settings_observer_browsertest.cc b/renderer/brave_content_settings_observer_browsertest.cc index dec12f801b06..125716acb786 100644 --- a/renderer/brave_content_settings_observer_browsertest.cc +++ b/renderer/brave_content_settings_observer_browsertest.cc @@ -17,6 +17,8 @@ #include "components/content_settings/core/common/content_settings.h" #include "components/content_settings/core/common/content_settings_types.h" #include "net/dns/mock_host_resolver.h" +#include "net/http/http_request_headers.h" +#include "net/test/embedded_test_server/http_request.h" const char kIframeID[] = "test"; @@ -61,10 +63,16 @@ class BraveContentSettingsObserverBrowserTest : public InProcessBrowserTest { base::PathService::Get(brave::DIR_TEST_DATA, &test_data_dir); embedded_test_server()->ServeFilesFromDirectory(test_data_dir); + embedded_test_server()->RegisterRequestMonitor( + base::BindRepeating( + &BraveContentSettingsObserverBrowserTest::SaveReferrer, + base::Unretained(this))); + ASSERT_TRUE(embedded_test_server()->Start()); url_ = embedded_test_server()->GetURL("a.com", "/iframe.html"); iframe_url_ = embedded_test_server()->GetURL("b.com", "/simple.html"); + image_url_ = embedded_test_server()->GetURL("b.com", "/logo.png"); top_level_page_pattern_ = ContentSettingsPattern::FromString("http://a.com/*"); iframe_pattern_ = ContentSettingsPattern::FromString("http://b.com/*"); @@ -72,6 +80,37 @@ class BraveContentSettingsObserverBrowserTest : public InProcessBrowserTest { ContentSettingsPattern::FromString("https://firstParty/*"); } + void SaveReferrer(const net::test_server::HttpRequest& request) { + base::AutoLock auto_lock(last_referrers_lock_); + + // Replace "127.0.0.1:" with the hostnames used in this test. + net::test_server::HttpRequest::HeaderMap::const_iterator pos = + request.headers.find(net::HttpRequestHeaders::kHost); + GURL::Replacements replace_host; + if (pos != request.headers.end()) { + replace_host.SetHostStr(pos->second); + replace_host.SetPortStr(""); // Host header includes the port already. + } + GURL request_url = request.GetURL(); + request_url = request_url.ReplaceComponents(replace_host); + + pos = request.headers.find(net::HttpRequestHeaders::kReferer); + if (pos == request.headers.end()) { + last_referrers_[request_url] = ""; // no referrer + } else { + last_referrers_[request_url] = pos->second; + } + } + + std::string GetLastReferrer(const GURL& url) const { + base::AutoLock auto_lock(last_referrers_lock_); + auto pos = last_referrers_.find(url); + if (pos == last_referrers_.end()) { + return "(missing)"; // Fail test if we haven't seen this URL before. + } + return pos->second; + } + void TearDown() override { browser_content_client_.reset(); content_client_.reset(); @@ -79,6 +118,18 @@ class BraveContentSettingsObserverBrowserTest : public InProcessBrowserTest { const GURL& url() { return url_; } const GURL& iframe_url() { return iframe_url_; } + const GURL& image_url() { return image_url_; } + + std::string create_image_script() { + std::string s; + s = " var img = document.createElement('img');" + " img.onload = function () {" + " domAutomationController.send(img.src);" + " };" + " img.src = '" + image_url().spec() + "';" + " document.body.appendChild(img);"; + return s; + } const ContentSettingsPattern& top_level_page_pattern() { return top_level_page_pattern_; @@ -269,11 +320,14 @@ class BraveContentSettingsObserverBrowserTest : public InProcessBrowserTest { private: GURL url_; GURL iframe_url_; + GURL image_url_; ContentSettingsPattern top_level_page_pattern_; ContentSettingsPattern first_party_pattern_; ContentSettingsPattern iframe_pattern_; std::unique_ptr content_client_; std::unique_ptr browser_content_client_; + mutable base::Lock last_referrers_lock_; + std::map last_referrers_; base::ScopedTempDir temp_user_data_dir_; }; @@ -472,35 +526,63 @@ IN_PROC_BROWSER_TEST_F(BraveContentSettingsObserverBrowserTest, EXPECT_EQ(settings.size(), 0u) << "There should not be any visible referrer rules."; + // The initial navigation doesn't have a referrer. NavigateToPageWithIframe(); - EXPECT_STREQ(ExecScriptGetStr(kReferrerScript, contents()).c_str(), ""); + EXPECT_TRUE(GetLastReferrer(url()).empty()); + + // Sub-resources loaded within the page get their referrer spoofed. + EXPECT_EQ(ExecScriptGetStr(create_image_script(), contents()), + image_url().spec()); + EXPECT_EQ(GetLastReferrer(image_url()), iframe_url().GetOrigin().spec()); + + // Cross-origin navigations get their referrers stripped. ASSERT_TRUE(NavigateIframeToURL(contents(), kIframeID, iframe_url())); ASSERT_EQ(child_frame()->GetLastCommittedURL(), iframe_url()); - EXPECT_STREQ(ExecScriptGetStr(kReferrerScript, - child_frame()).c_str(), iframe_url().GetOrigin().spec().c_str()); + EXPECT_TRUE(GetLastReferrer(iframe_url()).empty()); + EXPECT_STREQ(ExecScriptGetStr(kReferrerScript, child_frame()).c_str(), ""); } IN_PROC_BROWSER_TEST_F(BraveContentSettingsObserverBrowserTest, BlockReferrer) { BlockReferrers(); + + // The initial navigation doesn't have a referrer. NavigateToPageWithIframe(); EXPECT_STREQ(ExecScriptGetStr(kReferrerScript, contents()).c_str(), ""); + EXPECT_TRUE(GetLastReferrer(url()).empty()); + + // Sub-resources loaded within the page get their referrer spoofed. + EXPECT_EQ(ExecScriptGetStr(create_image_script(), contents()), + image_url().spec()); + EXPECT_EQ(GetLastReferrer(image_url()), image_url().GetOrigin().spec()); + + // Cross-origin navigations get their referrers stripped. ASSERT_TRUE(NavigateIframeToURL(contents(), kIframeID, iframe_url())); ASSERT_EQ(child_frame()->GetLastCommittedURL(), iframe_url()); - EXPECT_STREQ(ExecScriptGetStr(kReferrerScript, child_frame()).c_str(), - iframe_url().GetOrigin().spec().c_str()); + EXPECT_TRUE(GetLastReferrer(iframe_url()).empty()); + EXPECT_STREQ(ExecScriptGetStr(kReferrerScript, child_frame()).c_str(), ""); } IN_PROC_BROWSER_TEST_F(BraveContentSettingsObserverBrowserTest, AllowReferrer) { AllowReferrers(); - NavigateToPageWithIframe(); + // The initial navigation doesn't have a referrer. + NavigateToPageWithIframe(); EXPECT_STREQ(ExecScriptGetStr(kReferrerScript, contents()).c_str(), ""); + EXPECT_TRUE(GetLastReferrer(url()).empty()); + + // Sub-resources loaded within the page get the page URL as referrer. + EXPECT_EQ(ExecScriptGetStr(create_image_script(), contents()), + image_url().spec()); + EXPECT_EQ(GetLastReferrer(image_url()), url().spec()); + + // A cross-origin navigation gets the URL of the first one as referrer. ASSERT_TRUE(NavigateIframeToURL(contents(), kIframeID, iframe_url())); ASSERT_EQ(child_frame()->GetLastCommittedURL(), iframe_url()); + EXPECT_EQ(GetLastReferrer(iframe_url()), url()); EXPECT_STREQ(ExecScriptGetStr(kReferrerScript, child_frame()).c_str(), url().spec().c_str()); } @@ -508,11 +590,22 @@ IN_PROC_BROWSER_TEST_F(BraveContentSettingsObserverBrowserTest, AllowReferrer) { IN_PROC_BROWSER_TEST_F(BraveContentSettingsObserverBrowserTest, BlockReferrerShieldsDown) { BlockReferrers(); ShieldsDown(); + + // The initial navigation doesn't have a referrer. NavigateToPageWithIframe(); EXPECT_STREQ(ExecScriptGetStr(kReferrerScript, contents()).c_str(), ""); + EXPECT_TRUE(GetLastReferrer(url()).empty()); + + // Sub-resources loaded within the page get the page URL as referrer. + EXPECT_EQ(ExecScriptGetStr(create_image_script(), contents()), + image_url().spec()); + EXPECT_EQ(GetLastReferrer(image_url()), url().spec()); + + // A cross-origin navigation gets the URL of the first one as referrer. ASSERT_TRUE(NavigateIframeToURL(contents(), kIframeID, iframe_url())); ASSERT_EQ(child_frame()->GetLastCommittedURL(), iframe_url()); + EXPECT_EQ(GetLastReferrer(iframe_url()), url()); EXPECT_STREQ(ExecScriptGetStr(kReferrerScript, child_frame()).c_str(), url().spec().c_str()); }