Chromium Code Reviews| Index: chrome/renderer/extensions/resource_request_policy.cc |
| diff --git a/chrome/renderer/extensions/resource_request_policy.cc b/chrome/renderer/extensions/resource_request_policy.cc |
| index 0519a63fe5363c77ad5c83e97caa4cfbc6fca418..9aa0a07672ce402c5e2ecf6c19bb9fbcc1f1b902 100644 |
| --- a/chrome/renderer/extensions/resource_request_policy.cc |
| +++ b/chrome/renderer/extensions/resource_request_policy.cc |
| @@ -30,6 +30,30 @@ namespace extensions { |
| ResourceRequestPolicy::ResourceRequestPolicy(Dispatcher* dispatcher) |
| : dispatcher_(dispatcher) {} |
| +ResourceRequestPolicy::~ResourceRequestPolicy() = default; |
| + |
| +void ResourceRequestPolicy::OnExtensionLoaded(const Extension& extension) { |
| + if (WebAccessibleResourcesInfo::HasWebAccessibleResources(&extension) || |
| + // Extensions below manifest version 2 had all resources accessible by |
| + // default. |
| + // TODO(devlin): Two things - first, we might not have any v1 extensions |
| + // anymore; second, this should maybe be included in |
| + // HasWebAccessibleResources(). |
| + extension.manifest_version() < 2 || |
| + WebviewInfo::HasWebviewAccessibleResources( |
| + extension, dispatcher_->webview_partition_id()) || |
| + // Hosted app icons are accessible. |
| + // TODO(devlin): Should we incorporate this into |
| + // WebAccessibleResourcesInfo? |
| + (extension.is_hosted_app() && !IconsInfo::GetIcons(&extension).empty())) { |
| + web_accessible_ids_.insert(extension.id()); |
| + } |
| +} |
| + |
| +void ResourceRequestPolicy::OnExtensionUnloaded( |
| + const ExtensionId& extension_id) { |
| + web_accessible_ids_.erase(extension_id); |
| +} |
| // This method does a security check whether chrome-extension:// URLs can be |
| // requested by the renderer. Since this is in an untrusted process, the browser |
| @@ -42,11 +66,63 @@ bool ResourceRequestPolicy::CanRequestResource( |
| ui::PageTransition transition_type) { |
| CHECK(resource_url.SchemeIs(kExtensionScheme)); |
| + GURL frame_url = frame->GetDocument().Url(); |
| + |
| + // The page_origin may be GURL("null") for unique origins like data URLs, |
| + // but this is ok for the checks below. We only care if it matches the |
| + // current extension or has a devtools scheme. |
| + GURL page_origin = url::Origin(frame->Top()->GetSecurityOrigin()).GetURL(); |
| + |
| + GURL extension_origin = resource_url.GetOrigin(); |
| + |
| + // We always allow loads in the following cases, regardless of web accessible |
| + // resources: |
| + |
| + // Empty urls (needed for some edge cases when we have empty urls). |
| + if (frame_url.is_empty()) |
| + return true; |
| + |
| + // Extensions requesting their own resources (frame_url check is for images, |
| + // page_url check is for iframes). |
| + // TODO(devlin): We should be checking the ancestor chain, not just the |
| + // top-level frame. Additionally, we should be checking the security origin |
| + // of the frame, to account for about:blank subframes being scripted by an |
| + // extension parent (though we'll still need the frame origin check for |
| + // sandboxed frames). |
| + if (frame_url.GetOrigin() == extension_origin || |
| + page_origin == extension_origin) { |
| + return true; |
| + } |
| + |
| + if (!ui::PageTransitionIsWebTriggerable(transition_type)) |
| + return true; |
| + |
| + // Unreachable web page error page (to allow showing the icon of the |
| + // unreachable app on this page). |
| + if (frame_url == content::kUnreachableWebDataURL) |
| + return true; |
| + |
| + bool is_dev_tools = page_origin.SchemeIs(content::kChromeDevToolsScheme); |
| + // Note: we check web_accessible_ids (rather than first looking up the |
|
lazyboy
2017/07/10 22:36:39
nit: |web_accessible_ids_|
I'd also expand this c
Devlin
2017/07/10 22:52:30
Done.
|
| + // extension in the registry and checking that) to be more resistant against |
| + // timing attacks. |
| + if (!is_dev_tools && !web_accessible_ids_.count(extension_origin.host())) |
| + return false; |
|
lazyboy
2017/07/10 22:36:39
This used to show "Denying load of ... " message b
Devlin
2017/07/10 22:52:30
It may have in some situations been useful, but ad
|
| + |
| const Extension* extension = |
| RendererExtensionRegistry::Get()->GetExtensionOrAppByURL(resource_url); |
| - if (!extension) { |
| + if (is_dev_tools && !extension) { |
|
lazyboy
2017/07/10 22:36:39
Can you fold this and if in line 124:
if (is_dev_
Devlin
2017/07/10 22:52:30
Done. That is a bit cleaner; thanks!
|
| // Allow the load in the case of a non-existent extension. We'll just get a |
| // 404 from the browser process. |
| + // TODO(devlin): Can this happen? Does devtools potentially make requests |
| + // to non-existent extensions? |
| + return true; |
| + } |
| + |
| + // Devtools (chrome-extension:// URLs are loaded into frames of devtools to |
| + // support the devtools extension APIs). |
| + if (is_dev_tools && |
| + !chrome_manifest_urls::GetDevToolsPage(extension).is_empty()) { |
| return true; |
| } |
| @@ -72,43 +148,15 @@ bool ResourceRequestPolicy::CanRequestResource( |
| !WebviewInfo::IsResourceWebviewAccessible( |
| extension, dispatcher_->webview_partition_id(), |
| resource_url.path())) { |
| - GURL frame_url = frame->GetDocument().Url(); |
| - |
| - // The page_origin may be GURL("null") for unique origins like data URLs, |
| - // but this is ok for the checks below. We only care if it matches the |
| - // current extension or has a devtools scheme. |
| - GURL page_origin = url::Origin(frame->Top()->GetSecurityOrigin()).GetURL(); |
| - |
| - // Exceptions are: |
| - // - empty origin (needed for some edge cases when we have empty origins) |
| - bool is_empty_origin = frame_url.is_empty(); |
| - // - extensions requesting their own resources (frame_url check is for |
| - // images, page_url check is for iframes) |
| - bool is_own_resource = frame_url.GetOrigin() == extension->url() || |
| - page_origin == extension->url(); |
| - // - devtools (chrome-extension:// URLs are loaded into frames of devtools |
| - // to support the devtools extension APIs) |
| - bool is_dev_tools = |
| - page_origin.SchemeIs(content::kChromeDevToolsScheme) && |
| - !chrome_manifest_urls::GetDevToolsPage(extension).is_empty(); |
| - bool transition_allowed = |
| - !ui::PageTransitionIsWebTriggerable(transition_type); |
| - // - unreachable web page error page (to allow showing the icon of the |
| - // unreachable app on this page) |
| - bool is_error_page = frame_url == content::kUnreachableWebDataURL; |
| - |
| - if (!is_empty_origin && !is_own_resource && |
| - !is_dev_tools && !transition_allowed && !is_error_page) { |
| - std::string message = base::StringPrintf( |
| - "Denying load of %s. Resources must be listed in the " |
| - "web_accessible_resources manifest key in order to be loaded by " |
| - "pages outside the extension.", |
| - resource_url.spec().c_str()); |
| - frame->AddMessageToConsole( |
| - blink::WebConsoleMessage(blink::WebConsoleMessage::kLevelError, |
| - blink::WebString::FromUTF8(message))); |
| - return false; |
| - } |
| + std::string message = base::StringPrintf( |
| + "Denying load of %s. Resources must be listed in the " |
| + "web_accessible_resources manifest key in order to be loaded by " |
| + "pages outside the extension.", |
| + resource_url.spec().c_str()); |
| + frame->AddMessageToConsole( |
| + blink::WebConsoleMessage(blink::WebConsoleMessage::kLevelError, |
| + blink::WebString::FromUTF8(message))); |
| + return false; |
| } |
| return true; |