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

Prevent brave wallet providers from being generated in third party iframe #13268

Merged
merged 1 commit into from
May 10, 2022
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
59 changes: 48 additions & 11 deletions browser/brave_wallet/solana_provider_renderer_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "content/public/common/content_client.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_mock_cert_verifier.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
Expand Down Expand Up @@ -440,22 +441,37 @@ class SolanaProviderRendererTest : public InProcessBrowserTest {
{});
}

void SetUpCommandLine(base::CommandLine* command_line) override {
InProcessBrowserTest::SetUpCommandLine(command_line);
mock_cert_verifier_.SetUpCommandLine(command_line);
}

void SetUpInProcessBrowserTestFixture() override {
InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
mock_cert_verifier_.SetUpInProcessBrowserTestFixture();
}

void TearDownInProcessBrowserTestFixture() override {
mock_cert_verifier_.TearDownInProcessBrowserTestFixture();
InProcessBrowserTest::TearDownInProcessBrowserTestFixture();
}

void SetUpOnMainThread() override {
InProcessBrowserTest::SetUpOnMainThread();
content::SetBrowserClientForTesting(&test_content_browser_client_);
mock_cert_verifier_.mock_cert_verifier()->set_default_result(net::OK);
host_resolver()->AddRule("*", "127.0.0.1");

embedded_test_server()->SetSSLConfig(net::EmbeddedTestServer::CERT_OK);

ASSERT_TRUE(test_server_handle_ =
embedded_test_server()->StartAndReturnHandle());

// This is intentional to trigger
// TestBraveContentBrowserClient::RegisterBrowserInterfaceBindersForFrame
NavigateToURLAndWaitForLoadStop(browser(), GURL("brave://settings"));
ASSERT_TRUE(
ui_test_utils::NavigateToURL(browser(), GURL("brave://settings")));

GURL url = embedded_test_server()->GetURL("/empty.html");
NavigateToURLAndWaitForLoadStop(browser(), url);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));

ASSERT_TRUE(base::FeatureList::IsEnabled(
brave_wallet::features::kNativeBraveWalletFeature));
Expand All @@ -465,11 +481,6 @@ class SolanaProviderRendererTest : public InProcessBrowserTest {
return browser->tab_strip_model()->GetActiveWebContents();
}

void NavigateToURLAndWaitForLoadStop(Browser* browser, const GURL& url) {
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser, url)) << ":" << url;
ASSERT_TRUE(WaitForLoadStop(web_contents(browser))) << ":" << url;
}

void ReloadAndWaitForLoadStop(Browser* browser) {
chrome::Reload(browser, WindowOpenDisposition::CURRENT_TAB);
ASSERT_TRUE(content::WaitForLoadStop(web_contents(browser)));
Expand All @@ -480,6 +491,7 @@ class SolanaProviderRendererTest : public InProcessBrowserTest {
base::test::ScopedFeatureList feature_list_;

private:
content::ContentMockCertVerifier mock_cert_verifier_;
net::test_server::EmbeddedTestServerHandle test_server_handle_;
};

Expand All @@ -501,7 +513,7 @@ IN_PROC_BROWSER_TEST_F(SolanaProviderDisabledTest, SolanaObject) {
IN_PROC_BROWSER_TEST_F(SolanaProviderRendererTest, Incognito) {
Browser* private_browser = CreateIncognitoBrowser(nullptr);
GURL url = embedded_test_server()->GetURL("/empty.html");
NavigateToURLAndWaitForLoadStop(private_browser, url);
ASSERT_TRUE(ui_test_utils::NavigateToURL(private_browser, url));

auto result = EvalJs(web_contents(private_browser), CheckSolanaProviderScript,
content::EXECUTE_SCRIPT_USE_MANUAL_REPLY);
Expand Down Expand Up @@ -979,7 +991,7 @@ IN_PROC_BROWSER_TEST_F(SolanaProviderRendererTest, NonConfigurable) {
browser()->profile()->GetPrefs(),
brave_wallet::mojom::DefaultWallet::BraveWallet);
GURL url = embedded_test_server()->GetURL("/empty.html");
NavigateToURLAndWaitForLoadStop(browser(), url);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
std::string overwrite =
R"(try {
Object.defineProperty(window, 'solana', {
Expand All @@ -992,3 +1004,28 @@ IN_PROC_BROWSER_TEST_F(SolanaProviderRendererTest, NonConfigurable) {
EXPECT_TRUE(
content::EvalJs(web_contents(browser()), overwrite).ExtractBool());
}

IN_PROC_BROWSER_TEST_F(SolanaProviderRendererTest, Block3PIframe) {
GURL top_url(embedded_test_server()->GetURL("a.com", "/iframe.html"));
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), top_url));
// third party
GURL iframe_url_3p(embedded_test_server()->GetURL("b.com", "/"));
EXPECT_TRUE(
NavigateIframeToURL(web_contents(browser()), "test", iframe_url_3p));

constexpr char kEvalSolana[] = R"(typeof window.solana === 'undefined')";

content::RenderFrameHost* main_frame =
web_contents(browser())->GetMainFrame();
auto* iframe_rfh = ChildFrameAt(main_frame, 0);
ASSERT_TRUE(iframe_rfh);
EXPECT_TRUE(content::EvalJs(iframe_rfh, kEvalSolana).ExtractBool());

// same party
GURL iframe_url_1p(embedded_test_server()->GetURL("a.com", "/"));
EXPECT_TRUE(
NavigateIframeToURL(web_contents(browser()), "test", iframe_url_1p));
iframe_rfh = ChildFrameAt(main_frame, 0);
ASSERT_TRUE(iframe_rfh);
EXPECT_FALSE(content::EvalJs(iframe_rfh, kEvalSolana).ExtractBool());
}
5 changes: 5 additions & 0 deletions renderer/brave_wallet/brave_wallet_render_frame_observer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ void BraveWalletRenderFrameObserver::DidCreateScriptContext(
js_ethereum_provider_.reset();
return;
}
// Wallet provider objects won't be generated for third party iframe
if (!render_frame()->IsMainFrame() &&
render_frame()->GetWebFrame()->IsCrossOriginToMainFrame()) {
return;
}

bool is_main_world = world_id == content::ISOLATED_WORLD_ID_GLOBAL;
if (!js_ethereum_provider_) {
Expand Down
53 changes: 46 additions & 7 deletions renderer/test/js_ethereum_provider_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_mock_cert_verifier.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "url/gurl.h"
Expand All @@ -41,18 +42,33 @@ class JSEthereumProviderBrowserTest : public InProcessBrowserTest {
brave::RegisterPathProvider();
base::FilePath test_data_dir;
base::PathService::Get(brave::DIR_TEST_DATA, &test_data_dir);
https_server_.SetSSLConfig(net::EmbeddedTestServer::CERT_OK);
https_server_.ServeFilesFromDirectory(test_data_dir);
}

~JSEthereumProviderBrowserTest() override = default;

void SetUpCommandLine(base::CommandLine* command_line) override {
InProcessBrowserTest::SetUpCommandLine(command_line);
mock_cert_verifier_.SetUpCommandLine(command_line);
}

void SetUpInProcessBrowserTestFixture() override {
InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
mock_cert_verifier_.SetUpInProcessBrowserTestFixture();
}

void TearDownInProcessBrowserTestFixture() override {
mock_cert_verifier_.TearDownInProcessBrowserTestFixture();
InProcessBrowserTest::TearDownInProcessBrowserTestFixture();
}

void SetUpOnMainThread() override {
InProcessBrowserTest::SetUpOnMainThread();

EXPECT_TRUE(https_server_.Start());
mock_cert_verifier_.mock_cert_verifier()->set_default_result(net::OK);
// Map all hosts to localhost.
host_resolver()->AddRule("*", "127.0.0.1");
EXPECT_TRUE(https_server_.Start());
}

content::WebContents* web_contents() {
Expand All @@ -74,14 +90,15 @@ class JSEthereumProviderBrowserTest : public InProcessBrowserTest {
}

protected:
content::ContentMockCertVerifier mock_cert_verifier_;
net::EmbeddedTestServer https_server_;
};

IN_PROC_BROWSER_TEST_F(JSEthereumProviderBrowserTest, AttachOnReload) {
brave_wallet::SetDefaultWallet(browser()->profile()->GetPrefs(),
brave_wallet::mojom::DefaultWallet::None);
const GURL url = https_server_.GetURL("/simple.html");
NavigateToURLAndWaitForLoadStop(url);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));

std::string command = "window.ethereum.isMetaMask";
EXPECT_TRUE(content::EvalJs(main_frame(), command)
Expand Down Expand Up @@ -112,7 +129,8 @@ IN_PROC_BROWSER_TEST_F(JSEthereumProviderBrowserTest,
DoNotAttachToChromePages) {
brave_wallet::SetDefaultWallet(browser()->profile()->GetPrefs(),
brave_wallet::mojom::DefaultWallet::None);
NavigateToURLAndWaitForLoadStop(GURL("chrome://newtab/"));
ASSERT_TRUE(
ui_test_utils::NavigateToURL(browser(), GURL("chrome://newtab/")));

std::string command = "window.ethereum.isMetaMask";
EXPECT_TRUE(content::EvalJs(main_frame(), command,
Expand All @@ -135,7 +153,7 @@ IN_PROC_BROWSER_TEST_F(JSEthereumProviderBrowserTest,

IN_PROC_BROWSER_TEST_F(JSEthereumProviderBrowserTest, NonWritable) {
const GURL url = https_server_.GetURL("/simple.html");
NavigateToURLAndWaitForLoadStop(url);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));

// window.ethereum.*
auto result =
Expand Down Expand Up @@ -164,7 +182,7 @@ IN_PROC_BROWSER_TEST_F(JSEthereumProviderBrowserTest, NonWritable) {
// See https://github.com/brave/brave-browser/issues/22213 for details
IN_PROC_BROWSER_TEST_F(JSEthereumProviderBrowserTest, IsMetaMaskWritable) {
const GURL url = https_server_.GetURL("/simple.html");
NavigateToURLAndWaitForLoadStop(url);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));

std::string overwrite =
"window.ethereum.isMetaMask = false;"
Expand All @@ -177,7 +195,7 @@ IN_PROC_BROWSER_TEST_F(JSEthereumProviderBrowserTest, NonConfigurable) {
browser()->profile()->GetPrefs(),
brave_wallet::mojom::DefaultWallet::BraveWallet);
const GURL url = https_server_.GetURL("/simple.html");
NavigateToURLAndWaitForLoadStop(url);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
std::string overwrite =
R"(try {
Object.defineProperty(window, 'ethereum', {
Expand All @@ -189,3 +207,24 @@ IN_PROC_BROWSER_TEST_F(JSEthereumProviderBrowserTest, NonConfigurable) {
)";
EXPECT_TRUE(content::EvalJs(main_frame(), overwrite).ExtractBool());
}

IN_PROC_BROWSER_TEST_F(JSEthereumProviderBrowserTest, Block3PIframe) {
GURL top_url(https_server_.GetURL("a.com", "/iframe.html"));
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), top_url));
// third party
GURL iframe_url_3p(https_server_.GetURL("b.com", "/"));
EXPECT_TRUE(NavigateIframeToURL(web_contents(), "test", iframe_url_3p));

constexpr char kEvalEthereum[] = R"(typeof window.ethereum === 'undefined')";

auto* iframe_rfh = ChildFrameAt(main_frame(), 0);
ASSERT_TRUE(iframe_rfh);
EXPECT_TRUE(content::EvalJs(iframe_rfh, kEvalEthereum).ExtractBool());

// same party
GURL iframe_url_1p(https_server_.GetURL("a.com", "/"));
EXPECT_TRUE(NavigateIframeToURL(web_contents(), "test", iframe_url_1p));
iframe_rfh = ChildFrameAt(main_frame(), 0);
ASSERT_TRUE(iframe_rfh);
EXPECT_FALSE(content::EvalJs(iframe_rfh, kEvalEthereum).ExtractBool());
}