Skip to content

Commit

Permalink
Strip xorigin navigation referrers instead of spoofing
Browse files Browse the repository at this point in the history
  • Loading branch information
fmarier committed Apr 8, 2019
1 parent 7e86bc8 commit ed95f2e
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 9 deletions.
5 changes: 4 additions & 1 deletion browser/brave_content_browser_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
13 changes: 11 additions & 2 deletions browser/brave_content_browser_client_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
105 changes: 99 additions & 6 deletions renderer/brave_content_settings_observer_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -61,24 +63,73 @@ 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/*");
first_party_pattern_ =
ContentSettingsPattern::FromString("https://firstParty/*");
}

void SaveReferrer(const net::test_server::HttpRequest& request) {
base::AutoLock auto_lock(last_referrers_lock_);

// Replace "127.0.0.1:<port>" 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();
}

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_;
Expand Down Expand Up @@ -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<ChromeContentClient> content_client_;
std::unique_ptr<BraveContentBrowserClient> browser_content_client_;
mutable base::Lock last_referrers_lock_;
std::map<GURL, std::string> last_referrers_;

base::ScopedTempDir temp_user_data_dir_;
};
Expand Down Expand Up @@ -472,47 +526,86 @@ 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());
}

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());
}
Expand Down

0 comments on commit ed95f2e

Please sign in to comment.