diff options
author | amit@chromium.org <amit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-13 21:33:40 +0000 |
---|---|---|
committer | amit@chromium.org <amit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-13 21:33:40 +0000 |
commit | d266ce8f18632331944edf0042cb5a138bb19919 (patch) | |
tree | d1fc49eacc7c8cca621874e62a7f9bf6a5ef16c9 /chrome_frame/utils.cc | |
parent | 17d4f3df2f94a479c9486a86737bcff756008781 (diff) | |
download | chromium_src-d266ce8f18632331944edf0042cb5a138bb19919.zip chromium_src-d266ce8f18632331944edf0042cb5a138bb19919.tar.gz chromium_src-d266ce8f18632331944edf0042cb5a138bb19919.tar.bz2 |
Restrict unsafe URLs in Chrome Frame
Further tighten down what URLs can be loaded in Chrome Frame.
Based on the feedback from the security review and code
inspection, restrict about: scheme only to about:blank
and about:version by default. Factor out logic blocking logic
including for URL zone checking so that all ActiveX, ActiveDoc
and NPAPI will follow the same path. As a result we now block
restricted URL zones in NPAPI instance as well.
Another side effect of this refactoring is that the registry
flag, EnableGcfProtocol, is replaced by AllowUnsafeURLs. If
If this flag is set, then all the security related checking
is turned off.
BUG=50741
TEST=By default gcf: works only for about:blank, about:version and
view-source of http and https. Setting AllowUnsafeURLs to a non
zero value should allow any URL be loaded via gcf:
Review URL: http://codereview.chromium.org/3159006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@56096 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome_frame/utils.cc')
-rw-r--r-- | chrome_frame/utils.cc | 142 |
1 files changed, 66 insertions, 76 deletions
diff --git a/chrome_frame/utils.cc b/chrome_frame/utils.cc index f60f6c0..c2eade6 100644 --- a/chrome_frame/utils.cc +++ b/chrome_frame/utils.cc @@ -41,16 +41,16 @@ const wchar_t kContentAttribName[] = L"content"; const wchar_t kXUACompatValue[] = L"x-ua-compatible"; const wchar_t kBodyTag[] = L"body"; const wchar_t kChromeContentPrefix[] = L"chrome="; +const char kGCFProtocol[] = "gcf"; const wchar_t kChromeProtocolPrefix[] = L"gcf:"; const wchar_t kChromeMimeType[] = L"application/chromepage"; const wchar_t kPatchProtocols[] = L"PatchProtocols"; -const wchar_t kChromeFrameAttachTabPattern[] = L"*?attach_external_tab&*"; static const wchar_t kChromeFrameConfigKey[] = L"Software\\Google\\ChromeFrame"; static const wchar_t kRenderInGCFUrlList[] = L"RenderInGcfUrls"; static const wchar_t kRenderInHostUrlList[] = L"RenderInHostUrls"; -static const wchar_t kEnableGCFProtocol[] = L"EnableGCFProtocol"; +static const wchar_t kAllowUnsafeURLs[] = L"AllowUnsafeURLs"; static const wchar_t kEnableGCFRendererByDefault[] = L"IsDefaultRenderer"; static const wchar_t kEnableBuggyBhoIntercept[] = L"EnableBuggyBhoIntercept"; @@ -62,7 +62,7 @@ static const wchar_t kChromeFramePersistNPAPIReg[] = L"PersistNPAPIReg"; const wchar_t kChromeFrameOmahaSuffix[] = L"-cf"; const wchar_t kDevChannelName[] = L"-dev"; -const wchar_t kChromeAttachExternalTabPrefix[] = L"?attach_external_tab"; +const char kAttachExternalTabPrefix[] = "attach_external_tab"; // Indicates that we are running in a test environment, where execptions, etc // are handled by the chrome test crash server. @@ -856,21 +856,19 @@ bool CheckForCFNavigation(IBrowserService* browser, bool clear_flag) { return ret; } -bool IsValidUrlScheme(const std::wstring& url, bool is_privileged) { - if (url.empty()) +bool IsValidUrlScheme(const GURL& url, bool is_privileged) { + if (url.is_empty()) return false; - GURL crack_url(url); - - if (crack_url.SchemeIs(chrome::kHttpScheme) || - crack_url.SchemeIs(chrome::kHttpsScheme) || - crack_url.SchemeIs(chrome::kAboutScheme)) + if (url.SchemeIs(chrome::kHttpScheme) || + url.SchemeIs(chrome::kHttpsScheme) || + url.SchemeIs(chrome::kAboutScheme)) return true; // Additional checking for view-source. Allow only http and https // URLs in view source. - if (crack_url.SchemeIs(chrome::kViewSourceScheme)) { - GURL sub_url(crack_url.path()); + if (url.SchemeIs(chrome::kViewSourceScheme)) { + GURL sub_url(url.path()); if (sub_url.SchemeIs(chrome::kHttpScheme) || sub_url.SchemeIs(chrome::kHttpsScheme)) return true; @@ -879,8 +877,8 @@ bool IsValidUrlScheme(const std::wstring& url, bool is_privileged) { } if (is_privileged && - (crack_url.SchemeIs(chrome::kDataScheme) || - crack_url.SchemeIs(chrome::kExtensionScheme))) + (url.SchemeIs(chrome::kDataScheme) || + url.SchemeIs(chrome::kExtensionScheme))) return true; return false; @@ -1270,49 +1268,34 @@ HRESULT ReadStream(IStream* stream, size_t size, std::string* data) { return hr; } -ChromeFrameUrl::ChromeFrameUrl() - : is_chrome_protocol_(false), - attach_to_external_tab_(false), - cookie_(0), - disposition_(0) { +ChromeFrameUrl::ChromeFrameUrl() { + Reset(); } bool ChromeFrameUrl::Parse(const std::wstring& url) { - bool ret = false; - if (url.empty()) - return ret; + Reset(); + parsed_url_ = GURL(url); - url_ = url; + if (parsed_url_.is_empty()) + return false; - attach_to_external_tab_ = MatchPatternWide(url.c_str(), - kChromeFrameAttachTabPattern); - is_chrome_protocol_ = StartsWith(url, kChromeProtocolPrefix, false); - DCHECK(!(attach_to_external_tab_ && is_chrome_protocol_)); + is_chrome_protocol_ = parsed_url_.SchemeIs(kGCFProtocol); if (is_chrome_protocol_) { - url_.erase(0, lstrlen(kChromeProtocolPrefix)); + parsed_url_ = GURL(url.c_str() + lstrlen(kChromeProtocolPrefix)); + return true; } - if (attach_to_external_tab_) { - ret = ParseAttachExternalTabUrl(); - } else { - ret = true; - } - return ret; + return ParseAttachExternalTabUrl(); } bool ChromeFrameUrl::ParseAttachExternalTabUrl() { - size_t attach_external_tab_start_pos = - url_.find(kChromeAttachExternalTabPrefix); - if (attach_external_tab_start_pos == std::wstring::npos) { - DLOG(ERROR) << "Invalid url:" << url_; - return false; + std::string query = parsed_url_.query(); + if (!StartsWithASCII(query, kAttachExternalTabPrefix, false)) { + return parsed_url_.is_valid(); } - std::wstring url = - url_.substr(attach_external_tab_start_pos, - url_.length() - attach_external_tab_start_pos); - - WStringTokenizer tokenizer(url, L"&"); + attach_to_external_tab_ = true; + StringTokenizer tokenizer(query, "&"); // Skip over kChromeAttachExternalTabPrefix tokenizer.GetNext(); // Read the following items in order. @@ -1323,79 +1306,86 @@ bool ChromeFrameUrl::ParseAttachExternalTabUrl() { // 5. dimension.width // 6. dimension.height. if (tokenizer.GetNext()) { - wchar_t* end_ptr = 0; - cookie_ = _wcstoui64(tokenizer.token().c_str(), &end_ptr, 10); + char* end_ptr = 0; + cookie_ = _strtoui64(tokenizer.token().c_str(), &end_ptr, 10); } else { return false; } if (tokenizer.GetNext()) { - disposition_ = _wtoi(tokenizer.token().c_str()); + disposition_ = atoi(tokenizer.token().c_str()); } else { return false; } if (tokenizer.GetNext()) { - dimensions_.set_x(_wtoi(tokenizer.token().c_str())); + dimensions_.set_x(atoi(tokenizer.token().c_str())); } else { return false; } if (tokenizer.GetNext()) { - dimensions_.set_y(_wtoi(tokenizer.token().c_str())); + dimensions_.set_y(atoi(tokenizer.token().c_str())); } else { return false; } if (tokenizer.GetNext()) { - dimensions_.set_width(_wtoi(tokenizer.token().c_str())); + dimensions_.set_width(atoi(tokenizer.token().c_str())); } else { return false; } if (tokenizer.GetNext()) { - dimensions_.set_height(_wtoi(tokenizer.token().c_str())); + dimensions_.set_height(atoi(tokenizer.token().c_str())); } else { return false; } return true; } -bool CanNavigateInFullTabMode(const ChromeFrameUrl& cf_url, - IInternetSecurityManager* security_manager) { - bool is_privileged = false; +void ChromeFrameUrl::Reset() { + attach_to_external_tab_ = false; + is_chrome_protocol_ = false; + cookie_ = 0; + dimensions_.SetRect(0, 0, 0, 0); + disposition_ = 0; +} - if (!IsValidUrlScheme(cf_url.url(), is_privileged)) { - DLOG(WARNING) << __FUNCTION__ << " Disallowing navigation to url: " - << cf_url.url(); +bool CanNavigate(const GURL& url, IInternetSecurityManager* security_manager, + bool is_privileged) { + if (!url.is_valid()) { + DLOG(ERROR) << "Invalid URL passed to InitiateNavigation: " << url; return false; } - if (security_manager) { - DWORD zone = URLZONE_INVALID; - security_manager->MapUrlToZone(cf_url.url().c_str(), &zone, 0); - if (zone == URLZONE_UNTRUSTED) { + // No sanity checks if unsafe URLs are allowed + if (GetConfigBool(false, kAllowUnsafeURLs)) + return true; + + if (!IsValidUrlScheme(url, is_privileged)) { + DLOG(WARNING) << __FUNCTION__ << " Disallowing navigation to url: " << url; + return false; + } + + // Allow only about:blank or about:version + if (url.SchemeIs(chrome::kAboutScheme)) { + if (!LowerCaseEqualsASCII(url.spec(), chrome::kAboutBlankURL) && + !LowerCaseEqualsASCII(url.spec(), chrome::kAboutVersionURL)) { DLOG(WARNING) << __FUNCTION__ - << " Disallowing navigation to restricted url: " - << cf_url.url(); + << " Disallowing navigation to about url: " << url; return false; } } - if (cf_url.is_chrome_protocol()) { - // Allow chrome protocol (gcf:) if - - // - explicitly enabled using registry - // - for gcf:attach_external_tab - // - for gcf:about and gcf:view-source - GURL crack_url(cf_url.url()); - bool allow_gcf_protocol = - GetConfigBool(false, kEnableGCFProtocol) || - crack_url.SchemeIs(chrome::kAboutScheme) || - crack_url.SchemeIs(chrome::kViewSourceScheme); - if (!allow_gcf_protocol) { + // Prevent navigations to URLs in untrusted zone, even in Firefox. + if (security_manager) { + DWORD zone = URLZONE_INVALID; + std::wstring unicode_url = UTF8ToWide(url.spec()); + security_manager->MapUrlToZone(unicode_url.c_str(), &zone, 0); + if (zone == URLZONE_UNTRUSTED) { DLOG(WARNING) << __FUNCTION__ - << " Disallowing navigation to gcf url: " - << cf_url.url(); + << " Disallowing navigation to restricted url: " << url; return false; } } |