Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strip referrer and origin headers in xorigin requests from a .onion (uplift to 1.33.x) #11186

Merged
merged 1 commit into from
Nov 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions browser/brave_content_browser_client_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,18 @@ IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientReferrerTest,
&referrer);
EXPECT_EQ(referrer->url, kExtensionUrl);

// Special rule for Onion services.
const GURL kOnionUrl("http://lwkjglkejslkgjel.onion/index.html");
referrer = kReferrer.Clone();
referrer->url = kOnionUrl;
client()->MaybeHideReferrer(browser()->profile(), kRequestUrl, kOnionUrl,
&referrer);
EXPECT_EQ(referrer->url, GURL()); // .onion -> normal
referrer = kReferrer.Clone();
client()->MaybeHideReferrer(browser()->profile(), kOnionUrl, kDocumentUrl,
&referrer);
EXPECT_EQ(referrer->url, kDocumentUrl.GetOrigin()); // normal -> .onion

// Allow referrers for certain URL.
content_settings()->SetContentSettingCustomScope(
ContentSettingsPattern::FromString(kDocumentUrl.GetOrigin().spec() + "*"),
Expand Down
189 changes: 186 additions & 3 deletions browser/net/brave_site_hacks_network_delegate_helper_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "base/strings/stringprintf.h"
#include "brave/common/brave_paths.h"
#include "brave/components/brave_shields/browser/brave_shields_util.h"
#include "brave/components/tor/onion_location_navigation_throttle.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
Expand Down Expand Up @@ -38,6 +39,10 @@ class BraveSiteHacksNetworkDelegateBrowserTest : public InProcessBrowserTest {
https_server_.AddDefaultHandlers(GetChromeTestDataDir());
content::SetupCrossSiteRedirector(&https_server_);

https_server_.RegisterRequestMonitor(base::BindRepeating(
&BraveSiteHacksNetworkDelegateBrowserTest::HandleRequest,
base::Unretained(this)));

ASSERT_TRUE(https_server_.Start());

simple_landing_url_ = https_server_.GetURL("a.com", "/simple.html");
Expand All @@ -49,6 +54,39 @@ class BraveSiteHacksNetworkDelegateBrowserTest : public InProcessBrowserTest {
cross_site_url_ = https_server_.GetURL("b.com", "/navigate-to-site.html");
same_site_url_ =
https_server_.GetURL("sub.a.com", "/navigate-to-site.html");

onion_url_ = https_server_.GetURL("foobar.onion", "/navigate-to-site.html");
onion_post_url_ =
https_server_.GetURL("foobar.onion", "/post-to-site.html");
reflect_referrer_cross_origin_url_ =
https_server_.GetURL("a.com", "/reflect-referrer.html");
reflect_referrer_cross_origin_redirect_url_ = https_server_.GetURL(
"foobar.onion",
"/server-redirect-307?" + reflect_referrer_cross_origin_url_.spec());
reflect_referrer_same_origin_url_ =
https_server_.GetURL("foobar.onion", "/reflect-referrer.html");
reflect_referrer_same_origin_redirect_url_ = https_server_.GetURL(
"foobar.onion",
"/server-redirect-307?" + reflect_referrer_same_origin_url_.spec());
images_url_ = https_server_.GetURL("foobar.onion", "/referrer_images.html");
}

void HandleRequest(const net::test_server::HttpRequest& request) {
base::AutoLock auto_lock(last_headers_lock_);

auto referrer_it = request.headers.find("Referer");
if (referrer_it == request.headers.end()) {
last_referrer_[request.GetURL()] = "";
} else {
last_referrer_[request.GetURL()] = referrer_it->second;
}

auto origin_it = request.headers.find("Origin");
if (origin_it == request.headers.end()) {
last_origin_[request.GetURL()] = "";
} else {
last_origin_[request.GetURL()] = origin_it->second;
}
}

HostContentSettingsMap* content_settings() {
Expand All @@ -61,8 +99,6 @@ class BraveSiteHacksNetworkDelegateBrowserTest : public InProcessBrowserTest {
command_line->AppendSwitch(switches::kIgnoreCertificateErrors);
}

const net::EmbeddedTestServer& https_server() { return https_server_; }

GURL url(const GURL& destination_url, const GURL& navigation_url) {
std::string encoded_destination;
base::Base64UrlEncode(destination_url.spec(),
Expand Down Expand Up @@ -97,6 +133,45 @@ class BraveSiteHacksNetworkDelegateBrowserTest : public InProcessBrowserTest {
}
const GURL& same_site_url() { return same_site_url_; }

const GURL& onion_url() { return onion_url_; }
const GURL& onion_post_url() { return onion_post_url_; }
const GURL& reflect_referrer_cross_origin_url() {
return reflect_referrer_cross_origin_url_;
}
const GURL& reflect_referrer_cross_origin_redirect_url() {
return reflect_referrer_cross_origin_redirect_url_;
}
const GURL& reflect_referrer_same_origin_url() {
return reflect_referrer_same_origin_url_;
}
const GURL& reflect_referrer_same_origin_redirect_url() {
return reflect_referrer_same_origin_redirect_url_;
}

const GURL& images_url() { return images_url_; }
GURL image_url(const std::string& number) {
GURL::Replacements replacements;
replacements.SetPathStr("/logo-referrer.png");
replacements.SetQueryStr(number);
return images_url().ReplaceComponents(replacements);
}

const std::string& last_referrer(const GURL& url) {
base::AutoLock auto_lock(last_headers_lock_);
GURL::Replacements replacements;
replacements.SetHostStr("127.0.0.1");
const GURL internal_url = url.ReplaceComponents(replacements);
return last_referrer_[internal_url];
}

const std::string& last_origin(const GURL& url) {
base::AutoLock auto_lock(last_headers_lock_);
GURL::Replacements replacements;
replacements.SetHostStr("127.0.0.1");
const GURL internal_url = url.ReplaceComponents(replacements);
return last_origin_[internal_url];
}

content::WebContents* contents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}
Expand All @@ -119,8 +194,19 @@ class BraveSiteHacksNetworkDelegateBrowserTest : public InProcessBrowserTest {
GURL redirect_to_same_site_landing_url_;
GURL same_site_url_;
GURL simple_landing_url_;
base::FilePath test_data_dir_;

GURL onion_url_;
GURL onion_post_url_;
GURL reflect_referrer_cross_origin_url_;
GURL reflect_referrer_cross_origin_redirect_url_;
GURL reflect_referrer_same_origin_url_;
GURL reflect_referrer_same_origin_redirect_url_;
GURL images_url_;
std::map<GURL, std::string> last_referrer_;
std::map<GURL, std::string> last_origin_;
mutable base::Lock last_headers_lock_;

base::FilePath test_data_dir_;
net::test_server::EmbeddedTestServer https_server_;
};

Expand Down Expand Up @@ -256,3 +342,100 @@ IN_PROC_BROWSER_TEST_F(BraveSiteHacksNetworkDelegateBrowserTest,
EXPECT_EQ(contents()->GetLastCommittedURL(), output);
}
}

IN_PROC_BROWSER_TEST_F(BraveSiteHacksNetworkDelegateBrowserTest,
OnionReferrers) {
// Don't block the mock .onion requests.
tor::OnionLocationNavigationThrottle::BlockOnionRequestsOutsideTorForTesting(
false);

// Same-origin navigations
{
const GURL dest_url = reflect_referrer_same_origin_url();
const GURL same_origin_test_url = url(dest_url, onion_url());
NavigateToURLAndWaitForRedirects(same_origin_test_url, dest_url);
EXPECT_EQ(last_referrer(dest_url), same_origin_test_url.spec());
EXPECT_EQ(last_origin(dest_url), "");

// Redirect
const GURL intermediate_url = reflect_referrer_same_origin_redirect_url();
const GURL same_origin_redirect_test_url =
url(intermediate_url, onion_url());
NavigateToURLAndWaitForRedirects(same_origin_redirect_test_url, dest_url);
EXPECT_EQ(last_referrer(dest_url), same_origin_redirect_test_url.spec());
EXPECT_EQ(last_origin(dest_url), "");
}
{
// POST
const GURL dest_url = reflect_referrer_same_origin_url();
const GURL same_origin_test_url = url(dest_url, onion_post_url());
NavigateToURLAndWaitForRedirects(same_origin_test_url, dest_url);
EXPECT_EQ(last_referrer(dest_url), same_origin_test_url.spec());
std::string full_origin = same_origin_test_url.GetOrigin().spec();
full_origin.pop_back(); // CORS headers don't use canonical forms.
EXPECT_EQ(last_origin(dest_url), full_origin);

// Redirect
const GURL intermediate_url = reflect_referrer_same_origin_redirect_url();
const GURL same_origin_redirect_test_url =
url(intermediate_url, onion_post_url());
NavigateToURLAndWaitForRedirects(same_origin_redirect_test_url, dest_url);
EXPECT_EQ(last_referrer(dest_url), same_origin_redirect_test_url.spec());
EXPECT_EQ(last_origin(dest_url), full_origin);
}

// Cross-origin navigations
{
const GURL dest_url = reflect_referrer_cross_origin_url();
NavigateToURLAndWaitForRedirects(url(dest_url, onion_url()), dest_url);
EXPECT_EQ(last_referrer(dest_url), "");
EXPECT_EQ(last_origin(dest_url), "");

// Redirect
const GURL intermediate_url = reflect_referrer_cross_origin_redirect_url();
NavigateToURLAndWaitForRedirects(url(intermediate_url, onion_url()),
dest_url);
EXPECT_EQ(last_referrer(dest_url), "");
EXPECT_EQ(last_origin(dest_url), "");
}
{
// POST
const GURL dest_url = reflect_referrer_cross_origin_url();
NavigateToURLAndWaitForRedirects(url(dest_url, onion_post_url()), dest_url);
EXPECT_EQ(last_referrer(dest_url), "");
EXPECT_EQ(last_origin(dest_url), "null");

// Redirect
const GURL intermediate_url = reflect_referrer_cross_origin_redirect_url();
NavigateToURLAndWaitForRedirects(url(intermediate_url, onion_post_url()),
dest_url);
EXPECT_EQ(last_referrer(dest_url), "");
EXPECT_EQ(last_origin(dest_url), "null");
}

NavigateToURLAndWaitForRedirects(images_url(), images_url());

// Same-origin sub-requests
std::string full_origin = images_url().GetOrigin().spec();
full_origin.pop_back(); // CORS headers don't use canonical forms.
EXPECT_EQ(last_referrer(image_url("1")), images_url().spec());
EXPECT_EQ(last_origin(image_url("1")), ""); // nocors
EXPECT_EQ(last_referrer(image_url("2")), images_url().spec());
EXPECT_EQ(last_origin(image_url("2")), full_origin);
// Redirects
EXPECT_EQ(last_referrer(image_url("3")), images_url().spec());
EXPECT_EQ(last_origin(image_url("3")), ""); // nocors
EXPECT_EQ(last_referrer(image_url("4")), images_url().spec());
EXPECT_EQ(last_origin(image_url("4")), full_origin);

// Cross-origin sub-requests
EXPECT_EQ(last_referrer(image_url("5")), "");
EXPECT_EQ(last_origin(image_url("5")), ""); // nocors
EXPECT_EQ(last_referrer(image_url("6")), "");
EXPECT_EQ(last_origin(image_url("6")), "null");
// Redirects
EXPECT_EQ(last_referrer(image_url("7")), "");
EXPECT_EQ(last_origin(image_url("7")), ""); // nocors
EXPECT_EQ(last_referrer(image_url("8")), "");
EXPECT_EQ(last_origin(image_url("8")), "null");
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "brave/browser/net/url_context.h"
#include "brave/common/network_constants.h"
#include "net/base/net_errors.h"
#include "net/url_request/url_request_job.h"
#include "testing/gtest/include/gtest/gtest.h"

using brave::ResponseCallback;
Expand Down Expand Up @@ -100,6 +101,23 @@ TEST(BraveSiteHacksNetworkDelegateHelperTest,
}
}

TEST(BraveSiteHacksNetworkDelegateHelperTest, OnionReferrerStripped) {
const GURL original_referrer(
"https://"
"brave4u7jddbv7cyviptqjc7jusxh72uik7zt6adtckl5f4nwy2v72qd.onion/");
const GURL destination("https://brave.com");

// Cross-origin request from a .onion gets empty referrer.
auto url1 = net::URLRequestJob::ComputeReferrerForPolicy(
net::ReferrerPolicy::NEVER_CLEAR, original_referrer, destination);
EXPECT_EQ(url1, GURL());

// Cross-origin request to a .onion gets normal referrer.
auto url2 = net::URLRequestJob::ComputeReferrerForPolicy(
net::ReferrerPolicy::NEVER_CLEAR, destination, original_referrer);
EXPECT_EQ(url2, destination.GetOrigin());
}

TEST(BraveSiteHacksNetworkDelegateHelperTest, QueryStringUntouched) {
const std::vector<const std::string> urls({
"https://example.com/",
Expand Down
26 changes: 26 additions & 0 deletions chromium_src/net/url_request/url_request_job.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* Copyright 2021 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 https://mozilla.org/MPL/2.0/. */

#include "net/url_request/url_request_job.h"

// Strip referrer for cross-origin requests from a .onion hostname.
// This also affects the Origin header outside of CORS requests.
#define ComputeReferrerForPolicy \
ComputeReferrerForPolicy( \
ReferrerPolicy policy, const GURL& original_referrer, \
const GURL& destination, bool* same_origin_out_for_metrics) { \
if (base::EndsWith(original_referrer.host_piece(), ".onion", \
base::CompareCase::INSENSITIVE_ASCII) && \
!url::IsSameOriginWith(original_referrer, destination)) { \
return GURL(); \
} \
return ComputeReferrerForPolicy_Chromium( \
policy, original_referrer, destination, same_origin_out_for_metrics); \
} \
GURL URLRequestJob::ComputeReferrerForPolicy_Chromium

#include "../../../../net/url_request/url_request_job.cc"

#undef ComputeReferrerForPolicy
19 changes: 19 additions & 0 deletions chromium_src/net/url_request/url_request_job.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/* Copyright 2021 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 https://mozilla.org/MPL/2.0/. */

#ifndef BRAVE_CHROMIUM_SRC_NET_URL_REQUEST_URL_REQUEST_JOB_H_
#define BRAVE_CHROMIUM_SRC_NET_URL_REQUEST_URL_REQUEST_JOB_H_

#define ComputeReferrerForPolicy \
ComputeReferrerForPolicy( \
ReferrerPolicy policy, const GURL& original_referrer, \
const GURL& destination, bool* same_origin_out_for_metrics = nullptr); \
static GURL ComputeReferrerForPolicy_Chromium

#include "../../../../net/url_request/url_request_job.h"

#undef ComputeReferrerForPolicy

#endif // BRAVE_CHROMIUM_SRC_NET_URL_REQUEST_URL_REQUEST_JOB_H_
3 changes: 3 additions & 0 deletions chromium_src/services/network/cors/DEPS
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include_rules = [
"+../../../../../services/network/cors",
]
18 changes: 18 additions & 0 deletions chromium_src/services/network/cors/cors_url_loader.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/* Copyright 2021 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 https://mozilla.org/MPL/2.0/. */

// Nullify the Origin header for cross-origin CORS requests
// originating from a .onion address.
#define BRAVE_CORS_URL_LOADER_START_REQUEST \
if (base::EndsWith(request_.request_initiator->host(), ".onion", \
base::CompareCase::INSENSITIVE_ASCII) && \
!request_.request_initiator->IsSameOriginWith( \
url::Origin::Create(request_.url))) { \
request_.headers.SetHeader(net::HttpRequestHeaders::kOrigin, \
url::Origin().Serialize()); \
} else /* NOLINT */

#include "../../../../../services/network/cors/cors_url_loader.cc"
#undef BRAVE_CORS_URL_LOADER_START_REQUEST
7 changes: 6 additions & 1 deletion components/tor/onion_location_navigation_throttle.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ bool GetOnionLocation(const net::HttpResponseHeaders* headers,

} // namespace

bool OnionLocationNavigationThrottle::
block_onion_requests_outside_tor_for_testing_ = true;

// static
std::unique_ptr<OnionLocationNavigationThrottle>
OnionLocationNavigationThrottle::MaybeCreateThrottleFor(
Expand Down Expand Up @@ -106,7 +109,9 @@ OnionLocationNavigationThrottle::WillStartRequest() {
OnionLocationTabHelper::SetOnionLocation(
navigation_handle()->GetWebContents(), url);
}
return content::NavigationThrottle::BLOCK_REQUEST;
return block_onion_requests_outside_tor_for_testing_
? content::NavigationThrottle::BLOCK_REQUEST
: content::NavigationThrottle::PROCEED;
} else {
OnionLocationTabHelper::SetOnionLocation(
navigation_handle()->GetWebContents(), GURL());
Expand Down
5 changes: 5 additions & 0 deletions components/tor/onion_location_navigation_throttle.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@ class OnionLocationNavigationThrottle : public content::NavigationThrottle {
ThrottleCheckResult WillStartRequest() override;
const char* GetNameForLogging() override;

static void BlockOnionRequestsOutsideTorForTesting(bool block) {
block_onion_requests_outside_tor_for_testing_ = block;
}

private:
static bool block_onion_requests_outside_tor_for_testing_;
bool is_tor_profile_ = false;

PrefService* pref_service_ = nullptr;
Expand Down
Loading