Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(303)

Side by Side Diff: chrome/renderer/extensions/resource_request_policy.cc

Issue 2958343002: [Extensions] Change renderer-side web accessible resource determination (Closed)
Patch Set: lazyboy's Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/renderer/extensions/resource_request_policy.h" 5 #include "chrome/renderer/extensions/resource_request_policy.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/strings/stringprintf.h" 8 #include "base/strings/stringprintf.h"
9 #include "chrome/common/extensions/chrome_manifest_url_handlers.h" 9 #include "chrome/common/extensions/chrome_manifest_url_handlers.h"
10 #include "chrome/common/url_constants.h" 10 #include "chrome/common/url_constants.h"
(...skipping 12 matching lines...) Expand all
23 #include "third_party/WebKit/public/web/WebDocument.h" 23 #include "third_party/WebKit/public/web/WebDocument.h"
24 #include "third_party/WebKit/public/web/WebLocalFrame.h" 24 #include "third_party/WebKit/public/web/WebLocalFrame.h"
25 #include "ui/base/page_transition_types.h" 25 #include "ui/base/page_transition_types.h"
26 #include "url/gurl.h" 26 #include "url/gurl.h"
27 #include "url/origin.h" 27 #include "url/origin.h"
28 28
29 namespace extensions { 29 namespace extensions {
30 30
31 ResourceRequestPolicy::ResourceRequestPolicy(Dispatcher* dispatcher) 31 ResourceRequestPolicy::ResourceRequestPolicy(Dispatcher* dispatcher)
32 : dispatcher_(dispatcher) {} 32 : dispatcher_(dispatcher) {}
33 ResourceRequestPolicy::~ResourceRequestPolicy() = default;
34
35 void ResourceRequestPolicy::OnExtensionLoaded(const Extension& extension) {
36 if (WebAccessibleResourcesInfo::HasWebAccessibleResources(&extension) ||
37 // Extensions below manifest version 2 had all resources accessible by
38 // default.
39 // TODO(devlin): Two things - first, we might not have any v1 extensions
40 // anymore; second, this should maybe be included in
41 // HasWebAccessibleResources().
42 extension.manifest_version() < 2 ||
43 WebviewInfo::HasWebviewAccessibleResources(
44 extension, dispatcher_->webview_partition_id()) ||
45 // Hosted app icons are accessible.
46 // TODO(devlin): Should we incorporate this into
47 // WebAccessibleResourcesInfo?
48 (extension.is_hosted_app() && !IconsInfo::GetIcons(&extension).empty())) {
49 web_accessible_ids_.insert(extension.id());
50 }
51 }
52
53 void ResourceRequestPolicy::OnExtensionUnloaded(
54 const ExtensionId& extension_id) {
55 web_accessible_ids_.erase(extension_id);
56 }
33 57
34 // This method does a security check whether chrome-extension:// URLs can be 58 // This method does a security check whether chrome-extension:// URLs can be
35 // requested by the renderer. Since this is in an untrusted process, the browser 59 // requested by the renderer. Since this is in an untrusted process, the browser
36 // has a similar check to enforce the policy, in case this process is exploited. 60 // has a similar check to enforce the policy, in case this process is exploited.
37 // If you are changing this function, ensure equivalent checks are added to 61 // If you are changing this function, ensure equivalent checks are added to
38 // extension_protocols.cc's AllowExtensionResourceLoad. 62 // extension_protocols.cc's AllowExtensionResourceLoad.
39 bool ResourceRequestPolicy::CanRequestResource( 63 bool ResourceRequestPolicy::CanRequestResource(
40 const GURL& resource_url, 64 const GURL& resource_url,
41 blink::WebLocalFrame* frame, 65 blink::WebLocalFrame* frame,
42 ui::PageTransition transition_type) { 66 ui::PageTransition transition_type) {
43 CHECK(resource_url.SchemeIs(kExtensionScheme)); 67 CHECK(resource_url.SchemeIs(kExtensionScheme));
44 68
69 GURL frame_url = frame->GetDocument().Url();
70
71 // The page_origin may be GURL("null") for unique origins like data URLs,
72 // but this is ok for the checks below. We only care if it matches the
73 // current extension or has a devtools scheme.
74 GURL page_origin = url::Origin(frame->Top()->GetSecurityOrigin()).GetURL();
75
76 GURL extension_origin = resource_url.GetOrigin();
77
78 // We always allow loads in the following cases, regardless of web accessible
79 // resources:
80
81 // Empty urls (needed for some edge cases when we have empty urls).
82 if (frame_url.is_empty())
83 return true;
84
85 // Extensions requesting their own resources (frame_url check is for images,
86 // page_url check is for iframes).
87 // TODO(devlin): We should be checking the ancestor chain, not just the
88 // top-level frame. Additionally, we should be checking the security origin
89 // of the frame, to account for about:blank subframes being scripted by an
90 // extension parent (though we'll still need the frame origin check for
91 // sandboxed frames).
92 if (frame_url.GetOrigin() == extension_origin ||
93 page_origin == extension_origin) {
94 return true;
95 }
96
97 if (!ui::PageTransitionIsWebTriggerable(transition_type))
98 return true;
99
100 // Unreachable web page error page (to allow showing the icon of the
101 // unreachable app on this page).
102 if (frame_url == content::kUnreachableWebDataURL)
103 return true;
104
105 bool is_dev_tools = page_origin.SchemeIs(content::kChromeDevToolsScheme);
106 // Note: we check |web_accessible_ids| (rather than first looking up the
lazyboy 2017/07/10 23:13:36 |web_accessible_ids_|
Devlin 2017/07/11 02:06:07 Whoops, done.
107 // extension in the registry and checking that) to be more resistant against
108 // timing attacks. This way, determining access for an extension that isn't
109 // installed takes the same amount of time as determining access for an
110 // extension with no web accessible resources. We aren't worried about any
111 // extensions with web accessible resources, since those are inherently
112 // identifiable.
113 if (!is_dev_tools && !web_accessible_ids_.count(extension_origin.host()))
114 return false;
115
45 const Extension* extension = 116 const Extension* extension =
46 RendererExtensionRegistry::Get()->GetExtensionOrAppByURL(resource_url); 117 RendererExtensionRegistry::Get()->GetExtensionOrAppByURL(resource_url);
47 if (!extension) { 118 if (is_dev_tools) {
48 // Allow the load in the case of a non-existent extension. We'll just get a 119 // Allow the load in the case of a non-existent extension. We'll just get a
49 // 404 from the browser process. 120 // 404 from the browser process.
50 return true; 121 // TODO(devlin): Can this happen? Does devtools potentially make requests
122 // to non-existent extensions?
123 if (!extension)
124 return true;
125 // Devtools (chrome-extension:// URLs are loaded into frames of devtools to
126 // support the devtools extension APIs).
127 if (!chrome_manifest_urls::GetDevToolsPage(extension).is_empty())
128 return true;
51 } 129 }
52 130
131 DCHECK(extension);
132
53 // Disallow loading of packaged resources for hosted apps. We don't allow 133 // Disallow loading of packaged resources for hosted apps. We don't allow
54 // hybrid hosted/packaged apps. The one exception is access to icons, since 134 // hybrid hosted/packaged apps. The one exception is access to icons, since
55 // some extensions want to be able to do things like create their own 135 // some extensions want to be able to do things like create their own
56 // launchers. 136 // launchers.
57 base::StringPiece resource_root_relative_path = 137 base::StringPiece resource_root_relative_path =
58 resource_url.path_piece().empty() ? base::StringPiece() 138 resource_url.path_piece().empty() ? base::StringPiece()
59 : resource_url.path_piece().substr(1); 139 : resource_url.path_piece().substr(1);
60 if (extension->is_hosted_app() && 140 if (extension->is_hosted_app() &&
61 !IconsInfo::GetIcons(extension) 141 !IconsInfo::GetIcons(extension)
62 .ContainsPath(resource_root_relative_path)) { 142 .ContainsPath(resource_root_relative_path)) {
63 LOG(ERROR) << "Denying load of " << resource_url.spec() << " from " 143 LOG(ERROR) << "Denying load of " << resource_url.spec() << " from "
64 << "hosted app."; 144 << "hosted app.";
65 return false; 145 return false;
66 } 146 }
67 147
68 // Disallow loading of extension resources which are not explicitly listed 148 // Disallow loading of extension resources which are not explicitly listed
69 // as web or WebView accessible if the manifest version is 2 or greater. 149 // as web or WebView accessible if the manifest version is 2 or greater.
70 if (!WebAccessibleResourcesInfo::IsResourceWebAccessible( 150 if (!WebAccessibleResourcesInfo::IsResourceWebAccessible(
71 extension, resource_url.path()) && 151 extension, resource_url.path()) &&
72 !WebviewInfo::IsResourceWebviewAccessible( 152 !WebviewInfo::IsResourceWebviewAccessible(
73 extension, dispatcher_->webview_partition_id(), 153 extension, dispatcher_->webview_partition_id(),
74 resource_url.path())) { 154 resource_url.path())) {
75 GURL frame_url = frame->GetDocument().Url(); 155 std::string message = base::StringPrintf(
76 156 "Denying load of %s. Resources must be listed in the "
77 // The page_origin may be GURL("null") for unique origins like data URLs, 157 "web_accessible_resources manifest key in order to be loaded by "
78 // but this is ok for the checks below. We only care if it matches the 158 "pages outside the extension.",
79 // current extension or has a devtools scheme. 159 resource_url.spec().c_str());
80 GURL page_origin = url::Origin(frame->Top()->GetSecurityOrigin()).GetURL(); 160 frame->AddMessageToConsole(
81 161 blink::WebConsoleMessage(blink::WebConsoleMessage::kLevelError,
82 // Exceptions are: 162 blink::WebString::FromUTF8(message)));
83 // - empty origin (needed for some edge cases when we have empty origins) 163 return false;
84 bool is_empty_origin = frame_url.is_empty();
85 // - extensions requesting their own resources (frame_url check is for
86 // images, page_url check is for iframes)
87 bool is_own_resource = frame_url.GetOrigin() == extension->url() ||
88 page_origin == extension->url();
89 // - devtools (chrome-extension:// URLs are loaded into frames of devtools
90 // to support the devtools extension APIs)
91 bool is_dev_tools =
92 page_origin.SchemeIs(content::kChromeDevToolsScheme) &&
93 !chrome_manifest_urls::GetDevToolsPage(extension).is_empty();
94 bool transition_allowed =
95 !ui::PageTransitionIsWebTriggerable(transition_type);
96 // - unreachable web page error page (to allow showing the icon of the
97 // unreachable app on this page)
98 bool is_error_page = frame_url == content::kUnreachableWebDataURL;
99
100 if (!is_empty_origin && !is_own_resource &&
101 !is_dev_tools && !transition_allowed && !is_error_page) {
102 std::string message = base::StringPrintf(
103 "Denying load of %s. Resources must be listed in the "
104 "web_accessible_resources manifest key in order to be loaded by "
105 "pages outside the extension.",
106 resource_url.spec().c_str());
107 frame->AddMessageToConsole(
108 blink::WebConsoleMessage(blink::WebConsoleMessage::kLevelError,
109 blink::WebString::FromUTF8(message)));
110 return false;
111 }
112 } 164 }
113 165
114 return true; 166 return true;
115 } 167 }
116 168
117 } // namespace extensions 169 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/renderer/extensions/resource_request_policy.h ('k') | extensions/common/manifest_handlers/webview_info.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698