Skip to content

Commit

Permalink
Uplift of #10760 (squashed) to beta
Browse files Browse the repository at this point in the history
  • Loading branch information
brave-browser-releases committed Nov 19, 2021
1 parent 5edfaa6 commit a035f37
Show file tree
Hide file tree
Showing 17 changed files with 380 additions and 4 deletions.
12 changes: 12 additions & 0 deletions browser/brave_content_browser_client_browsertest.cc
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
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");
}
18 changes: 18 additions & 0 deletions browser/net/brave_site_hacks_network_delegate_helper_unittest.cc
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
@@ -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
@@ -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
@@ -0,0 +1,3 @@
include_rules = [
"+../../../../../services/network/cors",
]
18 changes: 18 additions & 0 deletions chromium_src/services/network/cors/cors_url_loader.cc
@@ -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
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
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

0 comments on commit a035f37

Please sign in to comment.