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

Side by Side Diff: content/child/site_isolation_policy.cc

Issue 1181493002: [Patch 3 of 6] Split out content/child's SiteIsolationPolicy into two new classes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@rename_policy_to_sniffer2
Patch Set: Add crbug. Created 5 years, 6 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 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 "content/child/site_isolation_policy.h" 5 #include "content/child/site_isolation_policy.h"
6 6
7 #include "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/lazy_instance.h" 9 #include "base/lazy_instance.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/metrics/histogram.h" 11 #include "base/metrics/histogram.h"
12 #include "base/strings/string_util.h" 12 #include "base/strings/string_util.h"
13 #include "content/public/common/content_switches.h" 13 #include "content/public/common/content_switches.h"
14 #include "content/public/common/resource_response_info.h" 14 #include "content/public/common/resource_response_info.h"
15 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" 15 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
16 #include "net/http/http_response_headers.h" 16 #include "net/http/http_response_headers.h"
17 17
18 using base::StringPiece; 18 using base::StringPiece;
19 19
20 namespace content { 20 namespace content {
21 21
22 namespace { 22 namespace {
23 23
24 // The cross-site document blocking/UMA data collection is deactivated by 24 // The gathering of UMA stats for site isolation is deactivated by default, and
25 // default, and only activated in renderer processes. 25 // only activated in renderer processes.
26 static bool g_policy_enabled = false; 26 static bool g_stats_gathering_enabled = false;
27 27
28 // MIME types 28 // MIME types
29 const char kTextHtml[] = "text/html"; 29 const char kTextHtml[] = "text/html";
30 const char kTextXml[] = "text/xml"; 30 const char kTextXml[] = "text/xml";
31 const char xAppRssXml[] = "application/rss+xml"; 31 const char xAppRssXml[] = "application/rss+xml";
32 const char kAppXml[] = "application/xml"; 32 const char kAppXml[] = "application/xml";
33 const char kAppJson[] = "application/json"; 33 const char kAppJson[] = "application/json";
34 const char kTextJson[] = "text/json"; 34 const char kTextJson[] = "text/json";
35 const char kTextXjson[] = "text/x-json"; 35 const char kTextXjson[] = "text/x-json";
36 const char kTextPlain[] = "text/plain"; 36 const char kTextPlain[] = "text/plain";
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 IncrementHistogramCount(bucket_prefix + ".NotBlocked"); 125 IncrementHistogramCount(bucket_prefix + ".NotBlocked");
126 if (sniffed_as_js) 126 if (sniffed_as_js)
127 IncrementHistogramCount(bucket_prefix + ".NotBlocked.MaybeJS"); 127 IncrementHistogramCount(bucket_prefix + ".NotBlocked.MaybeJS");
128 } 128 }
129 129
130 } // namespace 130 } // namespace
131 131
132 SiteIsolationResponseMetaData::SiteIsolationResponseMetaData() { 132 SiteIsolationResponseMetaData::SiteIsolationResponseMetaData() {
133 } 133 }
134 134
135 void SiteIsolationPolicy::SetPolicyEnabled(bool enabled) { 135 void SiteIsolationStatsGatherer::SetEnabled(bool enabled) {
136 g_policy_enabled = enabled; 136 g_stats_gathering_enabled = enabled;
137 } 137 }
138 138
139 linked_ptr<SiteIsolationResponseMetaData> 139 linked_ptr<SiteIsolationResponseMetaData>
140 SiteIsolationPolicy::OnReceivedResponse(const GURL& frame_origin, 140 SiteIsolationStatsGatherer::OnReceivedResponse(
141 const GURL& response_url, 141 const GURL& frame_origin,
142 ResourceType resource_type, 142 const GURL& response_url,
143 int origin_pid, 143 ResourceType resource_type,
144 const ResourceResponseInfo& info) { 144 int origin_pid,
145 if (!g_policy_enabled) 145 const ResourceResponseInfo& info) {
146 if (!g_stats_gathering_enabled)
146 return linked_ptr<SiteIsolationResponseMetaData>(); 147 return linked_ptr<SiteIsolationResponseMetaData>();
147 148
148 // if |origin_pid| is non-zero, it means that this response is for a plugin 149 // if |origin_pid| is non-zero, it means that this response is for a plugin
149 // spawned from this renderer process. We exclude responses for plugins for 150 // spawned from this renderer process. We exclude responses for plugins for
150 // now, but eventually, we're going to make plugin processes directly talk to 151 // now, but eventually, we're going to make plugin processes directly talk to
151 // the browser process so that we don't apply cross-site document blocking to 152 // the browser process so that we don't apply cross-site document blocking to
152 // them. 153 // them.
153 if (origin_pid) 154 if (origin_pid)
154 return linked_ptr<SiteIsolationResponseMetaData>(); 155 return linked_ptr<SiteIsolationResponseMetaData>();
155 156
156 UMA_HISTOGRAM_COUNTS("SiteIsolation.AllResponses", 1); 157 UMA_HISTOGRAM_COUNTS("SiteIsolation.AllResponses", 1);
157 158
158 // See if this is for navigation. If it is, don't block it, under the 159 // See if this is for navigation. If it is, don't block it, under the
159 // assumption that we will put it in an appropriate process. 160 // assumption that we will put it in an appropriate process.
160 if (IsResourceTypeFrame(resource_type)) 161 if (IsResourceTypeFrame(resource_type))
161 return linked_ptr<SiteIsolationResponseMetaData>(); 162 return linked_ptr<SiteIsolationResponseMetaData>();
162 163
163 if (!IsBlockableScheme(response_url)) 164 if (!CrossSiteDocumentClassifier::IsBlockableScheme(response_url))
164 return linked_ptr<SiteIsolationResponseMetaData>(); 165 return linked_ptr<SiteIsolationResponseMetaData>();
165 166
166 if (IsSameSite(frame_origin, response_url)) 167 if (CrossSiteDocumentClassifier::IsSameSite(frame_origin, response_url))
167 return linked_ptr<SiteIsolationResponseMetaData>(); 168 return linked_ptr<SiteIsolationResponseMetaData>();
168 169
169 SiteIsolationResponseMetaData::CanonicalMimeType canonical_mime_type = 170 SiteIsolationResponseMetaData::CanonicalMimeType canonical_mime_type =
170 GetCanonicalMimeType(info.mime_type); 171 CrossSiteDocumentClassifier::GetCanonicalMimeType(info.mime_type);
171 172
172 if (canonical_mime_type == SiteIsolationResponseMetaData::Others) 173 if (canonical_mime_type == SiteIsolationResponseMetaData::Others)
173 return linked_ptr<SiteIsolationResponseMetaData>(); 174 return linked_ptr<SiteIsolationResponseMetaData>();
174 175
175 // Every CORS request should have the Access-Control-Allow-Origin header even 176 // Every CORS request should have the Access-Control-Allow-Origin header even
176 // if it is preceded by a pre-flight request. Therefore, if this is a CORS 177 // if it is preceded by a pre-flight request. Therefore, if this is a CORS
177 // request, it has this header. response.httpHeaderField() internally uses 178 // request, it has this header. response.httpHeaderField() internally uses
178 // case-insensitive matching for the header name. 179 // case-insensitive matching for the header name.
179 std::string access_control_origin; 180 std::string access_control_origin;
180 181
181 // We can use a case-insensitive header name for EnumerateHeader(). 182 // We can use a case-insensitive header name for EnumerateHeader().
182 info.headers->EnumerateHeader(NULL, "access-control-allow-origin", 183 info.headers->EnumerateHeader(NULL, "access-control-allow-origin",
183 &access_control_origin); 184 &access_control_origin);
184 if (IsValidCorsHeaderSet(frame_origin, response_url, access_control_origin)) 185 if (CrossSiteDocumentClassifier::IsValidCorsHeaderSet(
186 frame_origin, response_url, access_control_origin))
185 return linked_ptr<SiteIsolationResponseMetaData>(); 187 return linked_ptr<SiteIsolationResponseMetaData>();
186 188
187 // Real XSD data collection starts from here. 189 // Real XSD data collection starts from here.
188 std::string no_sniff; 190 std::string no_sniff;
189 info.headers->EnumerateHeader(NULL, "x-content-type-options", &no_sniff); 191 info.headers->EnumerateHeader(NULL, "x-content-type-options", &no_sniff);
190 192
191 linked_ptr<SiteIsolationResponseMetaData> resp_data( 193 linked_ptr<SiteIsolationResponseMetaData> resp_data(
192 new SiteIsolationResponseMetaData); 194 new SiteIsolationResponseMetaData);
193 resp_data->frame_origin = frame_origin.spec(); 195 resp_data->frame_origin = frame_origin.spec();
194 resp_data->response_url = response_url; 196 resp_data->response_url = response_url;
195 resp_data->resource_type = resource_type; 197 resp_data->resource_type = resource_type;
196 resp_data->canonical_mime_type = canonical_mime_type; 198 resp_data->canonical_mime_type = canonical_mime_type;
197 resp_data->http_status_code = info.headers->response_code(); 199 resp_data->http_status_code = info.headers->response_code();
198 resp_data->no_sniff = base::LowerCaseEqualsASCII(no_sniff, "nosniff"); 200 resp_data->no_sniff = base::LowerCaseEqualsASCII(no_sniff, "nosniff");
199 201
200 return resp_data; 202 return resp_data;
201 } 203 }
202 204
203 bool SiteIsolationPolicy::OnReceivedFirstChunk( 205 bool SiteIsolationStatsGatherer::OnReceivedFirstChunk(
204 const linked_ptr<SiteIsolationResponseMetaData>& resp_data, 206 const linked_ptr<SiteIsolationResponseMetaData>& resp_data,
205 const char* raw_data, 207 const char* raw_data,
206 int raw_length) { 208 int raw_length) {
207 if (!g_policy_enabled) 209 if (!g_stats_gathering_enabled)
208 return false; 210 return false;
209 211
210 DCHECK(resp_data.get()); 212 DCHECK(resp_data.get());
211 213
212 StringPiece data(raw_data, raw_length); 214 StringPiece data(raw_data, raw_length);
213 215
214 // Record the length of the first received chunk of data to see if it's enough 216 // Record the length of the first received chunk of data to see if it's enough
215 // for sniffing. 217 // for sniffing.
216 UMA_HISTOGRAM_COUNTS("SiteIsolation.XSD.DataLength", raw_length); 218 UMA_HISTOGRAM_COUNTS("SiteIsolation.XSD.DataLength", raw_length);
217 219
218 // Record the number of cross-site document responses with a specific mime 220 // Record the number of cross-site document responses with a specific mime
219 // type (text/html, text/xml, etc). 221 // type (text/html, text/xml, etc).
220 UMA_HISTOGRAM_ENUMERATION( 222 UMA_HISTOGRAM_ENUMERATION(
221 "SiteIsolation.XSD.MimeType", resp_data->canonical_mime_type, 223 "SiteIsolation.XSD.MimeType", resp_data->canonical_mime_type,
222 SiteIsolationResponseMetaData::MaxCanonicalMimeType); 224 SiteIsolationResponseMetaData::MaxCanonicalMimeType);
223 225
224 // Store the result of cross-site document blocking analysis. 226 // Store the result of cross-site document blocking analysis.
225 bool would_block = false; 227 bool would_block = false;
226 bool sniffed_as_js = SniffForJS(data); 228 bool sniffed_as_js = SniffForJS(data);
227 229
228 // Record the number of responses whose content is sniffed for what its mime 230 // Record the number of responses whose content is sniffed for what its mime
229 // type claims it to be. For example, we apply a HTML sniffer for a document 231 // type claims it to be. For example, we apply a HTML sniffer for a document
230 // tagged with text/html here. Whenever this check becomes true, we'll block 232 // tagged with text/html here. Whenever this check becomes true, we'll block
231 // the response. 233 // the response.
232 if (resp_data->canonical_mime_type != SiteIsolationResponseMetaData::Plain) { 234 if (resp_data->canonical_mime_type != SiteIsolationResponseMetaData::Plain) {
233 std::string bucket_prefix; 235 std::string bucket_prefix;
234 bool sniffed_as_target_document = false; 236 bool sniffed_as_target_document = false;
235 if (resp_data->canonical_mime_type == SiteIsolationResponseMetaData::HTML) { 237 if (resp_data->canonical_mime_type == SiteIsolationResponseMetaData::HTML) {
236 bucket_prefix = "SiteIsolation.XSD.HTML"; 238 bucket_prefix = "SiteIsolation.XSD.HTML";
237 sniffed_as_target_document = SniffForHTML(data); 239 sniffed_as_target_document =
240 CrossSiteDocumentClassifier::SniffForHTML(data);
238 } else if (resp_data->canonical_mime_type == 241 } else if (resp_data->canonical_mime_type ==
239 SiteIsolationResponseMetaData::XML) { 242 SiteIsolationResponseMetaData::XML) {
240 bucket_prefix = "SiteIsolation.XSD.XML"; 243 bucket_prefix = "SiteIsolation.XSD.XML";
241 sniffed_as_target_document = SniffForXML(data); 244 sniffed_as_target_document =
245 CrossSiteDocumentClassifier::SniffForXML(data);
242 } else if (resp_data->canonical_mime_type == 246 } else if (resp_data->canonical_mime_type ==
243 SiteIsolationResponseMetaData::JSON) { 247 SiteIsolationResponseMetaData::JSON) {
244 bucket_prefix = "SiteIsolation.XSD.JSON"; 248 bucket_prefix = "SiteIsolation.XSD.JSON";
245 sniffed_as_target_document = SniffForJSON(data); 249 sniffed_as_target_document =
250 CrossSiteDocumentClassifier::SniffForJSON(data);
246 } else { 251 } else {
247 NOTREACHED() << "Not a blockable mime type: " 252 NOTREACHED() << "Not a blockable mime type: "
248 << resp_data->canonical_mime_type; 253 << resp_data->canonical_mime_type;
249 } 254 }
250 255
251 if (sniffed_as_target_document) { 256 if (sniffed_as_target_document) {
252 would_block = true; 257 would_block = true;
253 HistogramCountBlockedResponse(bucket_prefix, resp_data, false); 258 HistogramCountBlockedResponse(bucket_prefix, resp_data, false);
254 } else { 259 } else {
255 if (resp_data->no_sniff) { 260 if (resp_data->no_sniff) {
256 would_block = true; 261 would_block = true;
257 HistogramCountBlockedResponse(bucket_prefix, resp_data, true); 262 HistogramCountBlockedResponse(bucket_prefix, resp_data, true);
258 } else { 263 } else {
259 HistogramCountNotBlockedResponse(bucket_prefix, sniffed_as_js); 264 HistogramCountNotBlockedResponse(bucket_prefix, sniffed_as_js);
260 } 265 }
261 } 266 }
262 } else { 267 } else {
263 // This block is for plain text documents. We apply our HTML, XML, 268 // This block is for plain text documents. We apply our HTML, XML,
264 // and JSON sniffer to a text document in the order, and block it 269 // and JSON sniffer to a text document in the order, and block it
265 // if any of them succeeds in sniffing. 270 // if any of them succeeds in sniffing.
266 std::string bucket_prefix; 271 std::string bucket_prefix;
267 if (SniffForHTML(data)) 272 if (CrossSiteDocumentClassifier::SniffForHTML(data))
268 bucket_prefix = "SiteIsolation.XSD.Plain.HTML"; 273 bucket_prefix = "SiteIsolation.XSD.Plain.HTML";
269 else if (SniffForXML(data)) 274 else if (CrossSiteDocumentClassifier::SniffForXML(data))
270 bucket_prefix = "SiteIsolation.XSD.Plain.XML"; 275 bucket_prefix = "SiteIsolation.XSD.Plain.XML";
271 else if (SniffForJSON(data)) 276 else if (CrossSiteDocumentClassifier::SniffForJSON(data))
272 bucket_prefix = "SiteIsolation.XSD.Plain.JSON"; 277 bucket_prefix = "SiteIsolation.XSD.Plain.JSON";
273 278
274 if (bucket_prefix.size() > 0) { 279 if (bucket_prefix.size() > 0) {
275 would_block = true; 280 would_block = true;
276 HistogramCountBlockedResponse(bucket_prefix, resp_data, false); 281 HistogramCountBlockedResponse(bucket_prefix, resp_data, false);
277 } else if (resp_data->no_sniff) { 282 } else if (resp_data->no_sniff) {
278 would_block = true; 283 would_block = true;
279 HistogramCountBlockedResponse("SiteIsolation.XSD.Plain", resp_data, true); 284 HistogramCountBlockedResponse("SiteIsolation.XSD.Plain", resp_data, true);
280 } else { 285 } else {
281 HistogramCountNotBlockedResponse("SiteIsolation.XSD.Plain", 286 HistogramCountNotBlockedResponse("SiteIsolation.XSD.Plain",
282 sniffed_as_js); 287 sniffed_as_js);
283 } 288 }
284 } 289 }
285 290
286 return would_block; 291 return would_block;
287 } 292 }
288 293
289 SiteIsolationResponseMetaData::CanonicalMimeType 294 SiteIsolationResponseMetaData::CanonicalMimeType
290 SiteIsolationPolicy::GetCanonicalMimeType(const std::string& mime_type) { 295 CrossSiteDocumentClassifier::GetCanonicalMimeType(
296 const std::string& mime_type) {
291 if (base::LowerCaseEqualsASCII(mime_type, kTextHtml)) { 297 if (base::LowerCaseEqualsASCII(mime_type, kTextHtml)) {
292 return SiteIsolationResponseMetaData::HTML; 298 return SiteIsolationResponseMetaData::HTML;
293 } 299 }
294 300
295 if (base::LowerCaseEqualsASCII(mime_type, kTextPlain)) { 301 if (base::LowerCaseEqualsASCII(mime_type, kTextPlain)) {
296 return SiteIsolationResponseMetaData::Plain; 302 return SiteIsolationResponseMetaData::Plain;
297 } 303 }
298 304
299 if (base::LowerCaseEqualsASCII(mime_type, kAppJson) || 305 if (base::LowerCaseEqualsASCII(mime_type, kAppJson) ||
300 base::LowerCaseEqualsASCII(mime_type, kTextJson) || 306 base::LowerCaseEqualsASCII(mime_type, kTextJson) ||
301 base::LowerCaseEqualsASCII(mime_type, kTextXjson)) { 307 base::LowerCaseEqualsASCII(mime_type, kTextXjson)) {
302 return SiteIsolationResponseMetaData::JSON; 308 return SiteIsolationResponseMetaData::JSON;
303 } 309 }
304 310
305 if (base::LowerCaseEqualsASCII(mime_type, kTextXml) || 311 if (base::LowerCaseEqualsASCII(mime_type, kTextXml) ||
306 base::LowerCaseEqualsASCII(mime_type, xAppRssXml) || 312 base::LowerCaseEqualsASCII(mime_type, xAppRssXml) ||
307 base::LowerCaseEqualsASCII(mime_type, kAppXml)) { 313 base::LowerCaseEqualsASCII(mime_type, kAppXml)) {
308 return SiteIsolationResponseMetaData::XML; 314 return SiteIsolationResponseMetaData::XML;
309 } 315 }
310 316
311 return SiteIsolationResponseMetaData::Others; 317 return SiteIsolationResponseMetaData::Others;
312 } 318 }
313 319
314 bool SiteIsolationPolicy::IsBlockableScheme(const GURL& url) { 320 bool CrossSiteDocumentClassifier::IsBlockableScheme(const GURL& url) {
315 // We exclude ftp:// from here. FTP doesn't provide a Content-Type 321 // We exclude ftp:// from here. FTP doesn't provide a Content-Type
316 // header which our policy depends on, so we cannot protect any 322 // header which our policy depends on, so we cannot protect any
317 // document from FTP servers. 323 // document from FTP servers.
318 return url.SchemeIs(url::kHttpScheme) || url.SchemeIs(url::kHttpsScheme); 324 return url.SchemeIs(url::kHttpScheme) || url.SchemeIs(url::kHttpsScheme);
319 } 325 }
320 326
321 bool SiteIsolationPolicy::IsSameSite(const GURL& frame_origin, 327 bool CrossSiteDocumentClassifier::IsSameSite(const GURL& frame_origin,
322 const GURL& response_url) { 328 const GURL& response_url) {
323 if (!frame_origin.is_valid() || !response_url.is_valid()) 329 if (!frame_origin.is_valid() || !response_url.is_valid())
324 return false; 330 return false;
325 331
326 if (frame_origin.scheme() != response_url.scheme()) 332 if (frame_origin.scheme() != response_url.scheme())
327 return false; 333 return false;
328 334
329 // SameDomainOrHost() extracts the effective domains (public suffix plus one) 335 // SameDomainOrHost() extracts the effective domains (public suffix plus one)
330 // from the two URLs and compare them. 336 // from the two URLs and compare them.
331 return net::registry_controlled_domains::SameDomainOrHost( 337 return net::registry_controlled_domains::SameDomainOrHost(
332 frame_origin, response_url, 338 frame_origin, response_url,
333 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); 339 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
334 } 340 }
335 341
336 // We don't use Webkit's existing CORS policy implementation since 342 // We don't use Webkit's existing CORS policy implementation since
337 // their policy works in terms of origins, not sites. For example, 343 // their policy works in terms of origins, not sites. For example,
338 // when frame is sub.a.com and it is not allowed to access a document 344 // when frame is sub.a.com and it is not allowed to access a document
339 // with sub1.a.com. But under Site Isolation, it's allowed. 345 // with sub1.a.com. But under Site Isolation, it's allowed.
340 bool SiteIsolationPolicy::IsValidCorsHeaderSet( 346 bool CrossSiteDocumentClassifier::IsValidCorsHeaderSet(
341 const GURL& frame_origin, 347 const GURL& frame_origin,
342 const GURL& website_origin, 348 const GURL& website_origin,
343 const std::string& access_control_origin) { 349 const std::string& access_control_origin) {
344 // Many websites are sending back "\"*\"" instead of "*". This is 350 // Many websites are sending back "\"*\"" instead of "*". This is
345 // non-standard practice, and not supported by Chrome. Refer to 351 // non-standard practice, and not supported by Chrome. Refer to
346 // CrossOriginAccessControl::passesAccessControlCheck(). 352 // CrossOriginAccessControl::passesAccessControlCheck().
347 353
348 // TODO(dsjang): * is not allowed for the response from a request 354 // TODO(dsjang): * is not allowed for the response from a request
349 // with cookies. This allows for more than what the renderer will 355 // with cookies. This allows for more than what the renderer will
350 // eventually be able to receive, so we won't see illegal cross-site 356 // eventually be able to receive, so we won't see illegal cross-site
351 // documents allowed by this. We have to find a way to see if this 357 // documents allowed by this. We have to find a way to see if this
352 // response is from a cookie-tagged request or not in the future. 358 // response is from a cookie-tagged request or not in the future.
353 if (access_control_origin == "*") 359 if (access_control_origin == "*")
354 return true; 360 return true;
355 361
356 // TODO(dsjang): The CORS spec only treats a fully specified URL, except for 362 // TODO(dsjang): The CORS spec only treats a fully specified URL, except for
357 // "*", but many websites are using just a domain for access_control_origin, 363 // "*", but many websites are using just a domain for access_control_origin,
358 // and this is blocked by Webkit's CORS logic here : 364 // and this is blocked by Webkit's CORS logic here :
359 // CrossOriginAccessControl::passesAccessControlCheck(). GURL is set 365 // CrossOriginAccessControl::passesAccessControlCheck(). GURL is set
360 // is_valid() to false when it is created from a URL containing * in the 366 // is_valid() to false when it is created from a URL containing * in the
361 // domain part. 367 // domain part.
362 368
363 GURL cors_origin(access_control_origin); 369 GURL cors_origin(access_control_origin);
364 return IsSameSite(frame_origin, cors_origin); 370 return IsSameSite(frame_origin, cors_origin);
365 } 371 }
366 372
367 // This function is a slight modification of |net::SniffForHTML|. 373 // This function is a slight modification of |net::SniffForHTML|.
368 bool SiteIsolationPolicy::SniffForHTML(StringPiece data) { 374 bool CrossSiteDocumentClassifier::SniffForHTML(StringPiece data) {
369 // The content sniffer used by Chrome and Firefox are using "<!--" 375 // The content sniffer used by Chrome and Firefox are using "<!--"
370 // as one of the HTML signatures, but it also appears in valid 376 // as one of the HTML signatures, but it also appears in valid
371 // JavaScript, considered as well-formed JS by the browser. Since 377 // JavaScript, considered as well-formed JS by the browser. Since
372 // we do not want to block any JS, we exclude it from our HTML 378 // we do not want to block any JS, we exclude it from our HTML
373 // signatures. This can weaken our document block policy, but we can 379 // signatures. This can weaken our document block policy, but we can
374 // break less websites. 380 // break less websites.
375 // TODO(dsjang): parameterize |net::SniffForHTML| with an option 381 // TODO(dsjang): parameterize |net::SniffForHTML| with an option
376 // that decides whether to include <!-- or not, so that we can 382 // that decides whether to include <!-- or not, so that we can
377 // remove this function. 383 // remove this function.
378 // TODO(dsjang): Once SiteIsolationPolicy is moved into the browser 384 // TODO(dsjang): Once CrossSiteDocumentClassifier is moved into the browser
379 // process, we should do single-thread checking here for the static 385 // process, we should do single-thread checking here for the static
380 // initializer. 386 // initializer.
381 static const StringPiece kHtmlSignatures[] = { 387 static const StringPiece kHtmlSignatures[] = {
382 StringPiece("<!DOCTYPE html"), // HTML5 spec 388 StringPiece("<!DOCTYPE html"), // HTML5 spec
383 StringPiece("<script"), // HTML5 spec, Mozilla 389 StringPiece("<script"), // HTML5 spec, Mozilla
384 StringPiece("<html"), // HTML5 spec, Mozilla 390 StringPiece("<html"), // HTML5 spec, Mozilla
385 StringPiece("<head"), // HTML5 spec, Mozilla 391 StringPiece("<head"), // HTML5 spec, Mozilla
386 StringPiece("<iframe"), // Mozilla 392 StringPiece("<iframe"), // Mozilla
387 StringPiece("<h1"), // Mozilla 393 StringPiece("<h1"), // Mozilla
388 StringPiece("<div"), // Mozilla 394 StringPiece("<div"), // Mozilla
(...skipping 25 matching lines...) Expand all
414 if (offset == base::StringPiece::npos) 420 if (offset == base::StringPiece::npos)
415 break; 421 break;
416 422
417 // Proceed to the index next to the ending comment (-->). 423 // Proceed to the index next to the ending comment (-->).
418 data.remove_prefix(offset + strlen(kEndComment)); 424 data.remove_prefix(offset + strlen(kEndComment));
419 } 425 }
420 426
421 return false; 427 return false;
422 } 428 }
423 429
424 bool SiteIsolationPolicy::SniffForXML(base::StringPiece data) { 430 bool CrossSiteDocumentClassifier::SniffForXML(base::StringPiece data) {
425 // TODO(dsjang): Chrome's mime_sniffer is using strncasecmp() for 431 // TODO(dsjang): Chrome's mime_sniffer is using strncasecmp() for
426 // this signature. However, XML is case-sensitive. Don't we have to 432 // this signature. However, XML is case-sensitive. Don't we have to
427 // be more lenient only to block documents starting with the exact 433 // be more lenient only to block documents starting with the exact
428 // string <?xml rather than <?XML ? 434 // string <?xml rather than <?XML ?
429 // TODO(dsjang): Once SiteIsolationPolicy is moved into the browser 435 // TODO(dsjang): Once CrossSiteDocumentClassifier is moved into the browser
430 // process, we should do single-thread checking here for the static 436 // process, we should do single-thread checking here for the static
431 // initializer. 437 // initializer.
432 static const StringPiece kXmlSignatures[] = {StringPiece("<?xml")}; 438 static const StringPiece kXmlSignatures[] = {StringPiece("<?xml")};
433 return MatchesSignature(data, kXmlSignatures, arraysize(kXmlSignatures)); 439 return MatchesSignature(data, kXmlSignatures, arraysize(kXmlSignatures));
434 } 440 }
435 441
436 bool SiteIsolationPolicy::SniffForJSON(base::StringPiece data) { 442 bool CrossSiteDocumentClassifier::SniffForJSON(base::StringPiece data) {
437 // TODO(dsjang): We have to come up with a better way to sniff 443 // TODO(dsjang): We have to come up with a better way to sniff
438 // JSON. However, even RE cannot help us that much due to the fact 444 // JSON. However, even RE cannot help us that much due to the fact
439 // that we don't do full parsing. This DFA starts with state 0, and 445 // that we don't do full parsing. This DFA starts with state 0, and
440 // finds {, "/' and : in that order. We're avoiding adding a 446 // finds {, "/' and : in that order. We're avoiding adding a
441 // dependency on a regular expression library. 447 // dependency on a regular expression library.
442 enum { 448 enum {
443 kStartState, 449 kStartState,
444 kLeftBraceState, 450 kLeftBraceState,
445 kLeftQuoteState, 451 kLeftQuoteState,
446 kColonState, 452 kColonState,
(...skipping 25 matching lines...) Expand all
472 break; 478 break;
473 case kColonState: 479 case kColonState:
474 case kTerminalState: 480 case kTerminalState:
475 NOTREACHED(); 481 NOTREACHED();
476 break; 482 break;
477 } 483 }
478 } 484 }
479 return state == kColonState; 485 return state == kColonState;
480 } 486 }
481 487
482 bool SiteIsolationPolicy::SniffForJS(StringPiece data) { 488 bool SiteIsolationStatsGatherer::SniffForJS(StringPiece data) {
483 // TODO(dsjang): This is a real hack. The only purpose of this function is to 489 // The purpose of this function is to try to see if there's any possibility
484 // try to see if there's any possibility that this data can be JavaScript 490 // that this data can be JavaScript (superset of JS). Search for "var " for JS
485 // (superset of JS). This function will be removed once UMA stats are 491 // detection. This is a real hack and should only be used for stats gathering.
486 // gathered.
487
488 // Search for "var " for JS detection.
489 return data.find("var ") != base::StringPiece::npos; 492 return data.find("var ") != base::StringPiece::npos;
490 } 493 }
491 494
492 } // namespace content 495 } // namespace content
OLDNEW
« no previous file with comments | « content/child/site_isolation_policy.h ('k') | content/child/site_isolation_policy_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698