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 3 // found in the LICENSE file. 4 5 #include "chrome/renderer/extensions/resource_request_policy.h" 6 7 #include "base/command_line.h" 8 #include "base/logging.h" 9 #include "base/strings/stringprintf.h" 10 #include "chrome/common/chrome_switches.h" 11 #include "chrome/common/extensions/extension_set.h" 12 #include "chrome/common/extensions/manifest_handlers/icons_handler.h" 13 #include "chrome/common/extensions/manifest_url_handler.h" 14 #include "chrome/common/extensions/web_accessible_resources_handler.h" 15 #include "chrome/common/url_constants.h" 16 #include "content/public/common/page_transition_types.h" 17 #include "extensions/common/constants.h" 18 #include "extensions/common/extension.h" 19 #include "third_party/WebKit/public/platform/WebString.h" 20 #include "third_party/WebKit/public/web/WebConsoleMessage.h" 21 #include "third_party/WebKit/public/web/WebDocument.h" 22 #include "third_party/WebKit/public/web/WebFrame.h" 23 #include "url/gurl.h" 24 25 namespace extensions { 26 27 // This method does a security check whether chrome-extension:// URLs can be 28 // requested by the renderer. Since this is in an untrusted process, the browser 29 // has a similar check to enforce the policy, in case this process is exploited. 30 // If you are changing this function, ensure equivalent checks are added to 31 // extension_protocols.cc's AllowExtensionResourceLoad. 32 33 // static 34 bool ResourceRequestPolicy::CanRequestResource( 35 const GURL& resource_url, 36 blink::WebFrame* frame, 37 content::PageTransition transition_type, 38 const ExtensionSet* loaded_extensions) { 39 CHECK(resource_url.SchemeIs(extensions::kExtensionScheme)); 40 41 const Extension* extension = 42 loaded_extensions->GetExtensionOrAppByURL(resource_url); 43 if (!extension) { 44 // Allow the load in the case of a non-existent extension. We'll just get a 45 // 404 from the browser process. 46 return true; 47 } 48 49 // Disallow loading of packaged resources for hosted apps. We don't allow 50 // hybrid hosted/packaged apps. The one exception is access to icons, since 51 // some extensions want to be able to do things like create their own 52 // launchers. 53 std::string resource_root_relative_path = 54 resource_url.path().empty() ? std::string() 55 : resource_url.path().substr(1); 56 if (extension->is_hosted_app() && 57 !IconsInfo::GetIcons(extension) 58 .ContainsPath(resource_root_relative_path)) { 59 LOG(ERROR) << "Denying load of " << resource_url.spec() << " from " 60 << "hosted app."; 61 return false; 62 } 63 64 // Disallow loading of extension resources which are not explicitly listed 65 // as web accessible if the manifest version is 2 or greater. 66 if (!WebAccessibleResourcesInfo::IsResourceWebAccessible( 67 extension, resource_url.path()) && 68 !CommandLine::ForCurrentProcess()->HasSwitch( 69 switches::kDisableExtensionsResourceWhitelist)) { 70 GURL frame_url = frame->document().url(); 71 GURL page_url = frame->top()->document().url(); 72 73 // Exceptions are: 74 // - empty origin (needed for some edge cases when we have empty origins) 75 bool is_empty_origin = frame_url.is_empty(); 76 // - extensions requesting their own resources (frame_url check is for 77 // images, page_url check is for iframes) 78 bool is_own_resource = frame_url.GetOrigin() == extension->url() || 79 page_url.GetOrigin() == extension->url(); 80 // - devtools (chrome-extension:// URLs are loaded into frames of devtools 81 // to support the devtools extension APIs) 82 bool is_dev_tools = page_url.SchemeIs(chrome::kChromeDevToolsScheme) && 83 !ManifestURL::GetDevToolsPage(extension).is_empty(); 84 bool transition_allowed = 85 !content::PageTransitionIsWebTriggerable(transition_type); 86 // - unreachable web page error page (to allow showing the icon of the 87 // unreachable app on this page) 88 bool is_error_page = frame_url == GURL(content::kUnreachableWebDataURL); 89 90 if (!is_empty_origin && !is_own_resource && 91 !is_dev_tools && !transition_allowed && !is_error_page) { 92 std::string message = base::StringPrintf( 93 "Denying load of %s. Resources must be listed in the " 94 "web_accessible_resources manifest key in order to be loaded by " 95 "pages outside the extension.", 96 resource_url.spec().c_str()); 97 frame->addMessageToConsole( 98 blink::WebConsoleMessage(blink::WebConsoleMessage::LevelError, 99 blink::WebString::fromUTF8(message))); 100 return false; 101 } 102 } 103 104 return true; 105 } 106 107 // static 108 bool ResourceRequestPolicy::CanRequestExtensionResourceScheme( 109 const GURL& resource_url, 110 blink::WebFrame* frame) { 111 CHECK(resource_url.SchemeIs(chrome::kExtensionResourceScheme)); 112 113 GURL frame_url = frame->document().url(); 114 if (!frame_url.is_empty() && 115 !frame_url.SchemeIs(extensions::kExtensionScheme)) { 116 std::string message = base::StringPrintf( 117 "Denying load of %s. chrome-extension-resources:// can only be " 118 "loaded from extensions.", 119 resource_url.spec().c_str()); 120 frame->addMessageToConsole( 121 blink::WebConsoleMessage(blink::WebConsoleMessage::LevelError, 122 blink::WebString::fromUTF8(message))); 123 return false; 124 } 125 126 return true; 127 } 128 129 ResourceRequestPolicy::ResourceRequestPolicy() { 130 } 131 132 } // namespace extensions 133