Commit 67fac000 authored by dominicc's avatar dominicc Committed by Commit bot

Kill renderers that dink with Service Workers from non-secure origins.

The API use is checked on the Blink side, so these checks are to
thwart corrupted renderers. Specifically, renderers that try to
register, unregister or get registrations for non-secure origins must
be nuked from orbit. It's the only way to be sure.

BUG=394213
TEST=content_unittests ServiceWorkerDispatcherHostTest.*

Review URL: https://codereview.chromium.org/618113005

Cr-Commit-Position: refs/heads/master@{#297851}
parent cae7450f
......@@ -19,6 +19,7 @@
#include "content/common/service_worker/embedded_worker_messages.h"
#include "content/common/service_worker/service_worker_messages.h"
#include "ipc/ipc_message_macros.h"
#include "net/base/net_util.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerError.h"
#include "url/gurl.h"
......@@ -36,30 +37,41 @@ const uint32 kFilteredMessageClasses[] = {
EmbeddedWorkerMsgStart,
};
// TODO(dominicc): When crbug.com/362214 is fixed, make
// Can(R|Unr)egisterServiceWorker also check that these are secure
// origins to defend against compromised renderers.
bool AllOriginsMatch(const GURL& url_a, const GURL& url_b, const GURL& url_c) {
return url_a.GetOrigin() == url_b.GetOrigin() &&
url_a.GetOrigin() == url_c.GetOrigin();
}
// TODO(dominicc): When crbug.com/362214 is fixed use that to be
// consistent with Blink's
// SecurityOrigin::canAccessFeatureRequiringSecureOrigin.
bool OriginCanAccessServiceWorkers(const GURL& url) {
return url.SchemeIsSecure() || net::IsLocalhost(url.host());
}
bool CanRegisterServiceWorker(const GURL& document_url,
const GURL& pattern,
const GURL& script_url) {
// TODO: Respect Chrome's content settings, if we add a setting for
// controlling whether Service Worker is allowed.
return document_url.GetOrigin() == pattern.GetOrigin() &&
document_url.GetOrigin() == script_url.GetOrigin();
return AllOriginsMatch(document_url, pattern, script_url) &&
OriginCanAccessServiceWorkers(document_url);
}
bool CanUnregisterServiceWorker(const GURL& document_url,
const GURL& pattern) {
// TODO: Respect Chrome's content settings, if we add a setting for
// controlling whether Service Worker is allowed.
return document_url.GetOrigin() == pattern.GetOrigin();
return document_url.GetOrigin() == pattern.GetOrigin() &&
OriginCanAccessServiceWorkers(document_url);
}
bool CanGetRegistration(const GURL& document_url,
const GURL& given_document_url) {
// TODO: Respect Chrome's content settings, if we add a setting for
// controlling whether Service Worker is allowed.
return document_url.GetOrigin() == given_document_url.GetOrigin();
return document_url.GetOrigin() == given_document_url.GetOrigin() &&
OriginCanAccessServiceWorkers(document_url);
}
} // namespace
......
......@@ -124,12 +124,11 @@ class ServiceWorkerDispatcherHostTest : public testing::Test {
scoped_refptr<TestingServiceWorkerDispatcherHost> dispatcher_host_;
};
TEST_F(ServiceWorkerDispatcherHostTest, Register_SameOrigin) {
TEST_F(ServiceWorkerDispatcherHostTest, Register_HTTPS) {
const int64 kProviderId = 99; // Dummy value
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
host->SetDocumentUrl(GURL("https://www.example.com/foo"));
base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr();
context()->AddProviderHost(host.Pass());
Register(kProviderId,
......@@ -138,12 +137,37 @@ TEST_F(ServiceWorkerDispatcherHostTest, Register_SameOrigin) {
ServiceWorkerMsg_ServiceWorkerRegistered::ID);
}
TEST_F(ServiceWorkerDispatcherHostTest, Register_CrossOrigin) {
TEST_F(ServiceWorkerDispatcherHostTest, Register_NonSecureTransportLocalhost) {
const int64 kProviderId = 99; // Dummy value
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
host->SetDocumentUrl(GURL("http://127.0.0.3:81/foo"));
context()->AddProviderHost(host.Pass());
Register(kProviderId,
GURL("http://127.0.0.3:81/bar"),
GURL("http://127.0.0.3:81/baz"),
ServiceWorkerMsg_ServiceWorkerRegistered::ID);
}
TEST_F(ServiceWorkerDispatcherHostTest, Register_NonSecureOriginShouldFail) {
const int64 kProviderId = 99; // Dummy value
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
host->SetDocumentUrl(GURL("http://www.example.com/foo"));
context()->AddProviderHost(host.Pass());
SendRegister(kProviderId,
GURL("http://www.example.com/"),
GURL("http://www.example.com/bar"));
EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
}
TEST_F(ServiceWorkerDispatcherHostTest, Register_CrossOriginShouldFail) {
const int64 kProviderId = 99; // Dummy value
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
host->SetDocumentUrl(GURL("https://www.example.com/foo"));
base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr();
context()->AddProviderHost(host.Pass());
// Script has a different host
......@@ -170,7 +194,7 @@ TEST_F(ServiceWorkerDispatcherHostTest, Register_CrossOrigin) {
GURL("https://www.example.com/bar"));
EXPECT_EQ(4, dispatcher_host_->bad_messages_received_count_);
// Script and scope have different hosts
// Script and scope have a different host but match each other
SendRegister(kProviderId,
GURL("https://foo.example.com/"),
GURL("https://foo.example.com/bar"));
......@@ -183,28 +207,50 @@ TEST_F(ServiceWorkerDispatcherHostTest, Register_CrossOrigin) {
EXPECT_EQ(6, dispatcher_host_->bad_messages_received_count_);
}
TEST_F(ServiceWorkerDispatcherHostTest, Unregister_SameOrigin) {
TEST_F(ServiceWorkerDispatcherHostTest, Unregister_HTTPS) {
const int64 kProviderId = 99; // Dummy value
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
host->SetDocumentUrl(GURL("http://www.example.com/foo"));
base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr();
host->SetDocumentUrl(GURL("https://www.example.com/foo"));
context()->AddProviderHost(host.Pass());
Unregister(kProviderId,
GURL("https://www.example.com/"),
ServiceWorkerMsg_ServiceWorkerUnregistered::ID);
}
TEST_F(ServiceWorkerDispatcherHostTest,
Unregister_NonSecureTransportLocalhost) {
const int64 kProviderId = 99; // Dummy value
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
host->SetDocumentUrl(GURL("http://localhost/foo"));
context()->AddProviderHost(host.Pass());
Unregister(kProviderId,
GURL("http://www.example.com/"),
GURL("http://localhost/"),
ServiceWorkerMsg_ServiceWorkerUnregistered::ID);
}
TEST_F(ServiceWorkerDispatcherHostTest, Unregister_CrossOrigin) {
TEST_F(ServiceWorkerDispatcherHostTest, Unregister_CrossOriginShouldFail) {
const int64 kProviderId = 99; // Dummy value
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
host->SetDocumentUrl(GURL("https://www.example.com/foo"));
context()->AddProviderHost(host.Pass());
SendUnregister(kProviderId, GURL("https://foo.example.com/"));
EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
}
TEST_F(ServiceWorkerDispatcherHostTest, Unregister_NonSecureOriginShouldFail) {
const int64 kProviderId = 99; // Dummy value
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
host->SetDocumentUrl(GURL("http://www.example.com/foo"));
base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr();
context()->AddProviderHost(host.Pass());
SendUnregister(kProviderId, GURL("http://foo.example.com/"));
SendUnregister(kProviderId, GURL("http://www.example.com/"));
EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
}
......@@ -256,7 +302,6 @@ TEST_F(ServiceWorkerDispatcherHostTest, GetRegistration_SameOrigin) {
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
host->SetDocumentUrl(GURL("https://www.example.com/foo"));
base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr();
context()->AddProviderHost(host.Pass());
GetRegistration(kProviderId,
......@@ -264,18 +309,29 @@ TEST_F(ServiceWorkerDispatcherHostTest, GetRegistration_SameOrigin) {
ServiceWorkerMsg_DidGetRegistration::ID);
}
TEST_F(ServiceWorkerDispatcherHostTest, GetRegistration_CrossOrigin) {
TEST_F(ServiceWorkerDispatcherHostTest, GetRegistration_CrossOriginShouldFail) {
const int64 kProviderId = 99; // Dummy value
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
host->SetDocumentUrl(GURL("https://www.example.com/foo"));
base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr();
context()->AddProviderHost(host.Pass());
SendGetRegistration(kProviderId, GURL("https://foo.example.com/"));
EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
}
TEST_F(ServiceWorkerDispatcherHostTest,
GetRegistration_NotSecureOriginShouldFail) {
const int64 kProviderId = 99; // Dummy value
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
host->SetDocumentUrl(GURL("http://www.example.com/foo"));
context()->AddProviderHost(host.Pass());
SendGetRegistration(kProviderId, GURL("http://www.example.com/"));
EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
}
TEST_F(ServiceWorkerDispatcherHostTest, GetRegistration_EarlyContextDeletion) {
helper_->ShutdownContext();
......
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