Commit d7f5857f authored by Devlin Cronin's avatar Devlin Cronin Committed by Commit Bot

[Extensions] Force extensions XHR'ing the webstore to use CORS

Extensions are not allowed to inject scripts on the webstore, and
shouldn't be allowed to XHR it in a same-origin fashion. Instead, force
extension XHRs to the webstore to use CORS.

Bug: 826946

Change-Id: Ia38698a2e31931bc410c8e6ba10569706c9f3d90
Reviewed-on: https://chromium-review.googlesource.com/1012520
Commit-Queue: Devlin <rdevlin.cronin@chromium.org>
Reviewed-by: default avatarKaran Bhatia <karandeepb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#552099}
parent 28ab7b78
...@@ -6,23 +6,35 @@ ...@@ -6,23 +6,35 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_browsertest.h" #include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_io_data.h" #include "chrome/browser/profiles/profile_io_data.h"
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/ui_test_utils.h" #include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "extensions/browser/browsertest_util.h"
#include "extensions/common/extension.h" #include "extensions/common/extension.h"
#include "extensions/common/extension_urls.h"
#include "extensions/test/extension_test_message_listener.h"
#include "extensions/test/result_catcher.h" #include "extensions/test/result_catcher.h"
#include "extensions/test/test_extension_dir.h"
#include "net/base/escape.h" #include "net/base/escape.h"
#include "net/base/url_util.h" #include "net/base/url_util.h"
#include "net/dns/mock_host_resolver.h"
#include "net/ssl/client_cert_store.h" #include "net/ssl/client_cert_store.h"
#include "net/ssl/ssl_server_config.h" #include "net/ssl/ssl_server_config.h"
#include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/embedded_test_server.h"
#include "url/gurl.h" #include "url/gurl.h"
namespace extensions {
namespace { namespace {
constexpr const char kWebstoreDomain[] = "cws.com";
std::unique_ptr<net::ClientCertStore> CreateNullCertStore() { std::unique_ptr<net::ClientCertStore> CreateNullCertStore() {
return nullptr; return nullptr;
} }
...@@ -39,11 +51,11 @@ void InstallNullCertStoreFactoryOnIOThread( ...@@ -39,11 +51,11 @@ void InstallNullCertStoreFactoryOnIOThread(
class BackgroundXhrTest : public ExtensionBrowserTest { class BackgroundXhrTest : public ExtensionBrowserTest {
protected: protected:
void RunTest(const std::string& path, const GURL& url) { void RunTest(const std::string& path, const GURL& url) {
const extensions::Extension* extension = const Extension* extension =
LoadExtension(test_data_dir_.AppendASCII("background_xhr")); LoadExtension(test_data_dir_.AppendASCII("background_xhr"));
ASSERT_TRUE(extension); ASSERT_TRUE(extension);
extensions::ResultCatcher catcher; ResultCatcher catcher;
GURL test_url = net::AppendQueryParameter(extension->GetResourceURL(path), GURL test_url = net::AppendQueryParameter(extension->GetResourceURL(path),
"url", url.spec()); "url", url.spec());
ui_test_utils::NavigateToURL(browser(), test_url); ui_test_utils::NavigateToURL(browser(), test_url);
...@@ -83,3 +95,81 @@ IN_PROC_BROWSER_TEST_F(BackgroundXhrTest, HttpAuth) { ...@@ -83,3 +95,81 @@ IN_PROC_BROWSER_TEST_F(BackgroundXhrTest, HttpAuth) {
ASSERT_NO_FATAL_FAILURE(RunTest( ASSERT_NO_FATAL_FAILURE(RunTest(
"test_http_auth.html", embedded_test_server()->GetURL("/auth-basic"))); "test_http_auth.html", embedded_test_server()->GetURL("/auth-basic")));
} }
class BackgroundXhrWebstoreTest : public ExtensionApiTest {
public:
BackgroundXhrWebstoreTest() = default;
~BackgroundXhrWebstoreTest() override = default;
void SetUpCommandLine(base::CommandLine* command_line) override {
ExtensionApiTest::SetUpCommandLine(command_line);
// TODO(devlin): For some reason, trying to fetch an HTTPS url in this test
// fails (even when using an HTTPS EmbeddedTestServer). For this reason, we
// need to fake the webstore URLs as http versions.
command_line->AppendSwitchASCII(
::switches::kAppsGalleryURL,
base::StringPrintf("http://%s", kWebstoreDomain));
}
void SetUpOnMainThread() override {
ExtensionApiTest::SetUpOnMainThread();
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(embedded_test_server()->Start());
}
private:
DISALLOW_COPY_AND_ASSIGN(BackgroundXhrWebstoreTest);
};
// Extensions should not be able to XHR to the webstore.
IN_PROC_BROWSER_TEST_F(BackgroundXhrWebstoreTest, XHRToWebstore) {
TestExtensionDir test_dir;
test_dir.WriteManifest(R"(
{
"name": "XHR Test",
"manifest_version": 2,
"version": "0.1",
"background": {"scripts": ["background.js"]},
"permissions": ["<all_urls>"]
})");
constexpr char kBackgroundScriptFile[] =
R"(function canFetch(url) {
console.warn('Fetching: ' + url);
fetch(url).then((response) => {
domAutomationController.send('true');
}).catch((e) => {
domAutomationController.send('false');
});
}
chrome.test.sendMessage('ready');)";
test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), kBackgroundScriptFile);
ExtensionTestMessageListener listener("ready", false);
const Extension* extension = LoadExtension(test_dir.UnpackedPath());
ASSERT_TRUE(extension);
EXPECT_TRUE(listener.WaitUntilSatisfied());
content::BrowserContext* browser_context = profile();
auto can_fetch = [extension, browser_context](const GURL& url) {
std::string result = browsertest_util::ExecuteScriptInBackgroundPage(
browser_context, extension->id(),
base::StringPrintf("canFetch('%s');", url.spec().c_str()));
EXPECT_TRUE(result == "true" || result == "false")
<< "Unexpected result: " << result;
return result == "true";
};
GURL webstore_launch_url = extension_urls::GetWebstoreLaunchURL();
GURL webstore_url_to_fetch = embedded_test_server()->GetURL(
webstore_launch_url.host(), "/simple.html");
EXPECT_FALSE(can_fetch(webstore_url_to_fetch));
// Sanity check: the extension should be able to fetch google.com.
GURL google_url =
embedded_test_server()->GetURL("google.com", "/simple.html");
EXPECT_TRUE(can_fetch(google_url));
}
} // namespace extensions
...@@ -1237,6 +1237,15 @@ void Dispatcher::UpdateActiveExtensions() { ...@@ -1237,6 +1237,15 @@ void Dispatcher::UpdateActiveExtensions() {
void Dispatcher::InitOriginPermissions(const Extension* extension) { void Dispatcher::InitOriginPermissions(const Extension* extension) {
delegate_->InitOriginPermissions(extension, delegate_->InitOriginPermissions(extension,
IsExtensionActive(extension->id())); IsExtensionActive(extension->id()));
const GURL webstore_launch_url = extension_urls::GetWebstoreLaunchURL();
WebSecurityPolicy::AddOriginAccessBlacklistEntry(
extension->url(), WebString::FromUTF8(webstore_launch_url.scheme()),
WebString::FromUTF8(webstore_launch_url.host()), true);
// TODO(devlin): Should we also block the webstore update URL here? See
// https://crbug.com/826946 for a related instance.
UpdateOriginPermissions( UpdateOriginPermissions(
extension->url(), extension->url(),
URLPatternSet(), // No old permissions. URLPatternSet(), // No old permissions.
...@@ -1257,6 +1266,7 @@ void Dispatcher::UpdateOriginPermissions(const GURL& extension_url, ...@@ -1257,6 +1266,7 @@ void Dispatcher::UpdateOriginPermissions(const GURL& extension_url,
#endif #endif
extensions::kExtensionScheme, extensions::kExtensionScheme,
}; };
for (size_t i = 0; i < arraysize(kSchemes); ++i) { for (size_t i = 0; i < arraysize(kSchemes); ++i) {
const char* scheme = kSchemes[i]; const char* scheme = kSchemes[i];
// Remove all old patterns... // Remove all old patterns...
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment