1424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// found in the LICENSE file. 4424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 5424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "content/child/site_isolation_policy.h" 6424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 7424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/basictypes.h" 8424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/command_line.h" 94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/lazy_instance.h" 10424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/logging.h" 11424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/metrics/histogram.h" 12424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/strings/string_util.h" 13424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "content/public/common/content_switches.h" 14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "content/public/common/resource_response_info.h" 15424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "net/base/registry_controlled_domains/registry_controlled_domain.h" 16424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "net/http/http_response_headers.h" 17424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using base::StringPiece; 19424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 20424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)namespace content { 21424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 22424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)namespace { 23424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// The cross-site document blocking/UMA data collection is deactivated by 254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// default, and only activated in renderer processes. 264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)static bool g_policy_enabled = false; 274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 28424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// MIME types 29424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const char kTextHtml[] = "text/html"; 30424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const char kTextXml[] = "text/xml"; 31424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const char xAppRssXml[] = "application/rss+xml"; 32424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const char kAppXml[] = "application/xml"; 33424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const char kAppJson[] = "application/json"; 34424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const char kTextJson[] = "text/json"; 35424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const char kTextXjson[] = "text/x-json"; 36424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const char kTextPlain[] = "text/plain"; 37424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// TODO(dsjang): this is only needed for collecting UMA stat. Will be deleted 394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// when this class is used for actual blocking. 404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool IsRenderableStatusCode(int status_code) { 414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Chrome only uses the content of a response with one of these status codes 424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // for CSS/JavaScript. For images, Chrome just ignores status code. 434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const int renderable_status_code[] = {200, 201, 202, 203, 206, 300, 444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 301, 302, 303, 305, 306, 307}; 454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) for (size_t i = 0; i < arraysize(renderable_status_code); ++i) { 464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (renderable_status_code[i] == status_code) 474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; 484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return false; 504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool MatchesSignature(StringPiece data, 534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const StringPiece signatures[], 544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) size_t arr_size) { 55424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) size_t offset = data.find_first_not_of(" \t\r\n"); 574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // There is no not-whitespace character in this document. 584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (offset == base::StringPiece::npos) 594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return false; 60424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) data.remove_prefix(offset); 624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) size_t length = data.length(); 634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) for (size_t sig_index = 0; sig_index < arr_size; ++sig_index) { 654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const StringPiece& signature = signatures[sig_index]; 664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) size_t signature_length = signature.length(); 674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (length < signature_length) 684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) continue; 694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (LowerCaseEqualsASCII( 714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) data.begin(), data.begin() + signature_length, signature.data())) 724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; 734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return false; 754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void IncrementHistogramCount(const std::string& name) { 784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // The default value of min, max, bucket_count are copied from histogram.h. 794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::HistogramBase* histogram_pointer = base::Histogram::FactoryGet( 804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) name, 1, 100000, 50, base::HistogramBase::kUmaTargetedHistogramFlag); 814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) histogram_pointer->Add(1); 824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void IncrementHistogramEnum(const std::string& name, 854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) uint32 sample, 864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) uint32 boundary_value) { 874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // The default value of min, max, bucket_count are copied from histogram.h. 884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::HistogramBase* histogram_pointer = base::LinearHistogram::FactoryGet( 894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) name, 904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1, 914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) boundary_value, 924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) boundary_value + 1, 934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::HistogramBase::kUmaTargetedHistogramFlag); 944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) histogram_pointer->Add(sample); 954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void HistogramCountBlockedResponse( 984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const std::string& bucket_prefix, 99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) linked_ptr<SiteIsolationResponseMetaData>& resp_data, 1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bool nosniff_block) { 1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) std::string block_label(nosniff_block ? ".NoSniffBlocked" : ".Blocked"); 1024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) IncrementHistogramCount(bucket_prefix + block_label); 1034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // The content is blocked if it is sniffed as HTML/JSON/XML. When 1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // the blocked response is with an error status code, it is not 1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // disruptive for the following reasons : 1) the blocked content is 1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // not a binary object (such as an image) since it is sniffed as 1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // text; 2) then, this blocking only breaks the renderer behavior 1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // only if it is either JavaScript or CSS. However, the renderer 1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // doesn't use the contents of JS/CSS with unaffected status code 1114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // (e.g, 404). 3) the renderer is expected not to use the cross-site 1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // document content for purposes other than JS/CSS (e.g, XHR). 1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bool renderable_status_code = 114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) IsRenderableStatusCode(resp_data->http_status_code); 1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (renderable_status_code) { 1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) IncrementHistogramEnum( 1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bucket_prefix + block_label + ".RenderableStatusCode", 119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) resp_data->resource_type, 1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) RESOURCE_TYPE_LAST_TYPE); 1214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } else { 1224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) IncrementHistogramCount(bucket_prefix + block_label + 1234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ".NonRenderableStatusCode"); 1244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void HistogramCountNotBlockedResponse(const std::string& bucket_prefix, 1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bool sniffed_as_js) { 1294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) IncrementHistogramCount(bucket_prefix + ".NotBlocked"); 1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (sniffed_as_js) 1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) IncrementHistogramCount(bucket_prefix + ".NotBlocked.MaybeJS"); 1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} // namespace 1354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)SiteIsolationResponseMetaData::SiteIsolationResponseMetaData() {} 13758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 13858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void SiteIsolationPolicy::SetPolicyEnabled(bool enabled) { 13958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) g_policy_enabled = enabled; 14058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 14158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)linked_ptr<SiteIsolationResponseMetaData> 143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)SiteIsolationPolicy::OnReceivedResponse(const GURL& frame_origin, 144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const GURL& response_url, 1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ResourceType resource_type, 146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int origin_pid, 147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const ResourceResponseInfo& info) { 14858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!g_policy_enabled) 149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return linked_ptr<SiteIsolationResponseMetaData>(); 15058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 15158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // if |origin_pid| is non-zero, it means that this response is for a plugin 15258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // spawned from this renderer process. We exclude responses for plugins for 15358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // now, but eventually, we're going to make plugin processes directly talk to 15458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // the browser process so that we don't apply cross-site document blocking to 15558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // them. 15658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (origin_pid) 157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return linked_ptr<SiteIsolationResponseMetaData>(); 15858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 159424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) UMA_HISTOGRAM_COUNTS("SiteIsolation.AllResponses", 1); 160424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 161424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // See if this is for navigation. If it is, don't block it, under the 162424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // assumption that we will put it in an appropriate process. 1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (IsResourceTypeFrame(resource_type)) 164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return linked_ptr<SiteIsolationResponseMetaData>(); 165424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 166424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (!IsBlockableScheme(response_url)) 167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return linked_ptr<SiteIsolationResponseMetaData>(); 168424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 169424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (IsSameSite(frame_origin, response_url)) 170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return linked_ptr<SiteIsolationResponseMetaData>(); 171424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SiteIsolationResponseMetaData::CanonicalMimeType canonical_mime_type = 173424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) GetCanonicalMimeType(info.mime_type); 174424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (canonical_mime_type == SiteIsolationResponseMetaData::Others) 176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return linked_ptr<SiteIsolationResponseMetaData>(); 177424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 178424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // Every CORS request should have the Access-Control-Allow-Origin header even 179424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // if it is preceded by a pre-flight request. Therefore, if this is a CORS 180424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // request, it has this header. response.httpHeaderField() internally uses 181424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // case-insensitive matching for the header name. 182424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) std::string access_control_origin; 183424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 184424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // We can use a case-insensitive header name for EnumerateHeader(). 185424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) info.headers->EnumerateHeader( 186424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) NULL, "access-control-allow-origin", &access_control_origin); 187424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (IsValidCorsHeaderSet(frame_origin, response_url, access_control_origin)) 188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return linked_ptr<SiteIsolationResponseMetaData>(); 189424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 190424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // Real XSD data collection starts from here. 191424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) std::string no_sniff; 192424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) info.headers->EnumerateHeader(NULL, "x-content-type-options", &no_sniff); 193424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) linked_ptr<SiteIsolationResponseMetaData> resp_data( 195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) new SiteIsolationResponseMetaData); 196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) resp_data->frame_origin = frame_origin.spec(); 197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) resp_data->response_url = response_url; 198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) resp_data->resource_type = resource_type; 199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) resp_data->canonical_mime_type = canonical_mime_type; 200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) resp_data->http_status_code = info.headers->response_code(); 201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) resp_data->no_sniff = LowerCaseEqualsASCII(no_sniff, "nosniff"); 202424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 203a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return resp_data; 204424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 205424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 206424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)bool SiteIsolationPolicy::ShouldBlockResponse( 207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) linked_ptr<SiteIsolationResponseMetaData>& resp_data, 2084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const char* raw_data, 2094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int raw_length, 210424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) std::string* alternative_data) { 21158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!g_policy_enabled) 21258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return false; 21358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(resp_data.get()); 215424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 2164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) StringPiece data(raw_data, raw_length); 2174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 218424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // Record the length of the first received network packet to see if it's 219424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // enough for sniffing. 2204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) UMA_HISTOGRAM_COUNTS("SiteIsolation.XSD.DataLength", raw_length); 221424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 222424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // Record the number of cross-site document responses with a specific mime 223424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // type (text/html, text/xml, etc). 224424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION( 225424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) "SiteIsolation.XSD.MimeType", 226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) resp_data->canonical_mime_type, 227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SiteIsolationResponseMetaData::MaxCanonicalMimeType); 228424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 2294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Store the result of cross-site document blocking analysis. 2304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bool is_blocked = false; 2314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bool sniffed_as_js = SniffForJS(data); 232424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 233424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // Record the number of responses whose content is sniffed for what its mime 234424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // type claims it to be. For example, we apply a HTML sniffer for a document 235424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // tagged with text/html here. Whenever this check becomes true, we'll block 236424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // the response. 237a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (resp_data->canonical_mime_type != 238a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SiteIsolationResponseMetaData::Plain) { 2394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) std::string bucket_prefix; 2404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bool sniffed_as_target_document = false; 241a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (resp_data->canonical_mime_type == 242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SiteIsolationResponseMetaData::HTML) { 2434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bucket_prefix = "SiteIsolation.XSD.HTML"; 2444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) sniffed_as_target_document = SniffForHTML(data); 245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else if (resp_data->canonical_mime_type == 246a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SiteIsolationResponseMetaData::XML) { 2474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bucket_prefix = "SiteIsolation.XSD.XML"; 2484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) sniffed_as_target_document = SniffForXML(data); 249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else if (resp_data->canonical_mime_type == 250a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SiteIsolationResponseMetaData::JSON) { 2514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bucket_prefix = "SiteIsolation.XSD.JSON"; 2524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) sniffed_as_target_document = SniffForJSON(data); 2534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } else { 2544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) NOTREACHED() << "Not a blockable mime type: " 255a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) << resp_data->canonical_mime_type; 2564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 2574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (sniffed_as_target_document) { 2594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) is_blocked = true; 2604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) HistogramCountBlockedResponse(bucket_prefix, resp_data, false); 2614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } else { 262a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (resp_data->no_sniff) { 2634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) is_blocked = true; 2644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) HistogramCountBlockedResponse(bucket_prefix, resp_data, true); 2654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } else { 2664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) HistogramCountNotBlockedResponse(bucket_prefix, sniffed_as_js); 267424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 2684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 2694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } else { 2704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // This block is for plain text documents. We apply our HTML, XML, 2714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // and JSON sniffer to a text document in the order, and block it 2724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // if any of them succeeds in sniffing. 2734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) std::string bucket_prefix; 2744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (SniffForHTML(data)) 2754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bucket_prefix = "SiteIsolation.XSD.Plain.HTML"; 2764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) else if (SniffForXML(data)) 2774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bucket_prefix = "SiteIsolation.XSD.Plain.XML"; 2784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) else if (SniffForJSON(data)) 2794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bucket_prefix = "SiteIsolation.XSD.Plain.JSON"; 2804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (bucket_prefix.size() > 0) { 2824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) is_blocked = true; 2834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) HistogramCountBlockedResponse(bucket_prefix, resp_data, false); 284a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else if (resp_data->no_sniff) { 2854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) is_blocked = true; 2864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) HistogramCountBlockedResponse("SiteIsolation.XSD.Plain", resp_data, true); 2874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } else { 2884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) HistogramCountNotBlockedResponse("SiteIsolation.XSD.Plain", 2894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) sniffed_as_js); 2904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 291424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 292424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 2934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!CommandLine::ForCurrentProcess()->HasSwitch( 2944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) switches::kBlockCrossSiteDocuments)) 2954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) is_blocked = false; 296424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 2974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (is_blocked) { 298424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) alternative_data->erase(); 299424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) alternative_data->insert(0, " "); 300a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) LOG(ERROR) << resp_data->response_url 301424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) << " is blocked as an illegal cross-site document from " 302a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) << resp_data->frame_origin; 303424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 3044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return is_blocked; 305424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 306424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)SiteIsolationResponseMetaData::CanonicalMimeType 308424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)SiteIsolationPolicy::GetCanonicalMimeType(const std::string& mime_type) { 309424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (LowerCaseEqualsASCII(mime_type, kTextHtml)) { 310a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return SiteIsolationResponseMetaData::HTML; 311424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 312424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 313424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (LowerCaseEqualsASCII(mime_type, kTextPlain)) { 314a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return SiteIsolationResponseMetaData::Plain; 315424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 316424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 317424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (LowerCaseEqualsASCII(mime_type, kAppJson) || 318424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) LowerCaseEqualsASCII(mime_type, kTextJson) || 319424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) LowerCaseEqualsASCII(mime_type, kTextXjson)) { 320a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return SiteIsolationResponseMetaData::JSON; 321424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 322424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 323424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (LowerCaseEqualsASCII(mime_type, kTextXml) || 324424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) LowerCaseEqualsASCII(mime_type, xAppRssXml) || 325424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) LowerCaseEqualsASCII(mime_type, kAppXml)) { 326a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return SiteIsolationResponseMetaData::XML; 327424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 328424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 329a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return SiteIsolationResponseMetaData::Others; 330424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 331424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 332424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)bool SiteIsolationPolicy::IsBlockableScheme(const GURL& url) { 333424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // We exclude ftp:// from here. FTP doesn't provide a Content-Type 334424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // header which our policy depends on, so we cannot protect any 335424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // document from FTP servers. 3361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return url.SchemeIs(url::kHttpScheme) || url.SchemeIs(url::kHttpsScheme); 337424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 338424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 339424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)bool SiteIsolationPolicy::IsSameSite(const GURL& frame_origin, 340424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) const GURL& response_url) { 341424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 342424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (!frame_origin.is_valid() || !response_url.is_valid()) 343424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return false; 344424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 345424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (frame_origin.scheme() != response_url.scheme()) 346424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return false; 347424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 348424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // SameDomainOrHost() extracts the effective domains (public suffix plus one) 349424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // from the two URLs and compare them. 350424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return net::registry_controlled_domains::SameDomainOrHost( 351424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) frame_origin, 352424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) response_url, 3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); 354424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 355424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 356424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// We don't use Webkit's existing CORS policy implementation since 357424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// their policy works in terms of origins, not sites. For example, 358424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// when frame is sub.a.com and it is not allowed to access a document 359424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// with sub1.a.com. But under Site Isolation, it's allowed. 360424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)bool SiteIsolationPolicy::IsValidCorsHeaderSet( 3614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const GURL& frame_origin, 3624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const GURL& website_origin, 3634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const std::string& access_control_origin) { 364424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // Many websites are sending back "\"*\"" instead of "*". This is 365424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // non-standard practice, and not supported by Chrome. Refer to 366424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // CrossOriginAccessControl::passesAccessControlCheck(). 367424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 368424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // TODO(dsjang): * is not allowed for the response from a request 369424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // with cookies. This allows for more than what the renderer will 370424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // eventually be able to receive, so we won't see illegal cross-site 371424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // documents allowed by this. We have to find a way to see if this 372424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // response is from a cookie-tagged request or not in the future. 373424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (access_control_origin == "*") 374424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return true; 375424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 376424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // TODO(dsjang): The CORS spec only treats a fully specified URL, except for 377424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // "*", but many websites are using just a domain for access_control_origin, 378424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // and this is blocked by Webkit's CORS logic here : 379424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // CrossOriginAccessControl::passesAccessControlCheck(). GURL is set 380424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // is_valid() to false when it is created from a URL containing * in the 381424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // domain part. 382424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 383424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) GURL cors_origin(access_control_origin); 384424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return IsSameSite(frame_origin, cors_origin); 385424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 386424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 387424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// This function is a slight modification of |net::SniffForHTML|. 3884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool SiteIsolationPolicy::SniffForHTML(StringPiece data) { 389424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // The content sniffer used by Chrome and Firefox are using "<!--" 390424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // as one of the HTML signatures, but it also appears in valid 391424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // JavaScript, considered as well-formed JS by the browser. Since 392424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // we do not want to block any JS, we exclude it from our HTML 393424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // signatures. This can weaken our document block policy, but we can 394424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // break less websites. 395424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // TODO(dsjang): parameterize |net::SniffForHTML| with an option 396424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // that decides whether to include <!-- or not, so that we can 397424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // remove this function. 3984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // TODO(dsjang): Once SiteIsolationPolicy is moved into the browser 3994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // process, we should do single-thread checking here for the static 4004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // initializer. 4014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) static const StringPiece kHtmlSignatures[] = { 4024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) StringPiece("<!DOCTYPE html"), // HTML5 spec 4034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) StringPiece("<script"), // HTML5 spec, Mozilla 4044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) StringPiece("<html"), // HTML5 spec, Mozilla 4054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) StringPiece("<head"), // HTML5 spec, Mozilla 4064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) StringPiece("<iframe"), // Mozilla 4074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) StringPiece("<h1"), // Mozilla 4084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) StringPiece("<div"), // Mozilla 4094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) StringPiece("<font"), // Mozilla 4104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) StringPiece("<table"), // Mozilla 4114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) StringPiece("<a"), // Mozilla 4124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) StringPiece("<style"), // Mozilla 4134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) StringPiece("<title"), // Mozilla 4144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) StringPiece("<b"), // Mozilla 4154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) StringPiece("<body"), // Mozilla 4164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) StringPiece("<br"), // Mozilla 4174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) StringPiece("<p"), // Mozilla 4184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) StringPiece("<?xml") // Mozilla 419424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) }; 420424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 4214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) while (data.length() > 0) { 4224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (MatchesSignature( 4234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) data, kHtmlSignatures, arraysize(kHtmlSignatures))) 4244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; 425424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 4264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // If we cannot find "<!--", we fail sniffing this as HTML. 4274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) static const StringPiece kCommentBegins[] = { StringPiece("<!--") }; 4284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!MatchesSignature(data, kCommentBegins, arraysize(kCommentBegins))) 4294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) break; 430424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 431424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // Search for --> and do SniffForHTML after that. If we can find the 432424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // comment's end, we start HTML sniffing from there again. 4334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) static const char kEndComment[] = "-->"; 4344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) size_t offset = data.find(kEndComment); 4354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (offset == base::StringPiece::npos) 4364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) break; 4374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 4384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Proceed to the index next to the ending comment (-->). 4394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) data.remove_prefix(offset + strlen(kEndComment)); 440424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 441424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 442424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return false; 443424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 444424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 4454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool SiteIsolationPolicy::SniffForXML(base::StringPiece data) { 446424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // TODO(dsjang): Chrome's mime_sniffer is using strncasecmp() for 447424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // this signature. However, XML is case-sensitive. Don't we have to 448424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // be more lenient only to block documents starting with the exact 449424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // string <?xml rather than <?XML ? 4504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // TODO(dsjang): Once SiteIsolationPolicy is moved into the browser 4514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // process, we should do single-thread checking here for the static 4524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // initializer. 4534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) static const StringPiece kXmlSignatures[] = { StringPiece("<?xml") }; 4544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return MatchesSignature(data, kXmlSignatures, arraysize(kXmlSignatures)); 455424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 456424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 4574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool SiteIsolationPolicy::SniffForJSON(base::StringPiece data) { 458424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // TODO(dsjang): We have to come up with a better way to sniff 459424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // JSON. However, even RE cannot help us that much due to the fact 460424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // that we don't do full parsing. This DFA starts with state 0, and 461424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // finds {, "/' and : in that order. We're avoiding adding a 462424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // dependency on a regular expression library. 4634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) enum { 4644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) kStartState, 4654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) kLeftBraceState, 4664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) kLeftQuoteState, 4674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) kColonState, 4684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) kTerminalState, 4694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } state = kStartState; 4704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 4714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) size_t length = data.length(); 472424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) for (size_t i = 0; i < length && state < kColonState; ++i) { 473424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) const char c = data[i]; 474424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (c == ' ' || c == '\t' || c == '\r' || c == '\n') 475424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) continue; 476424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 477424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) switch (state) { 4784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) case kStartState: 479424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (c == '{') 480424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) state = kLeftBraceState; 481424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) else 4824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) state = kTerminalState; 483424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) break; 484424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) case kLeftBraceState: 485424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (c == '\"' || c == '\'') 486424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) state = kLeftQuoteState; 487424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) else 4884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) state = kTerminalState; 489424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) break; 490424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) case kLeftQuoteState: 491424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (c == ':') 492424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) state = kColonState; 493424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) break; 4944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) case kColonState: 4954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) case kTerminalState: 496424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) NOTREACHED(); 497424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) break; 498424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 499424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 500424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return state == kColonState; 501424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 502424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 5034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool SiteIsolationPolicy::SniffForJS(StringPiece data) { 504424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // TODO(dsjang): This is a real hack. The only purpose of this function is to 505424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // try to see if there's any possibility that this data can be JavaScript 506424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // (superset of JS). This function will be removed once UMA stats are 507424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // gathered. 508424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 509424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // Search for "var " for JS detection. 5104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return data.find("var ") != base::StringPiece::npos; 511424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 512424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 513424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} // namespace content 514