summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjaphet@chromium.org <japhet@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-04 18:30:09 +0000
committerjaphet@chromium.org <japhet@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-04 18:30:09 +0000
commit85cc78c5489a2925214a02aef4baf716d74bb1cc (patch)
treea9945e2369606d83d2977e94636fa35a8f45a765
parentae90f252d04c941f8ff9e7a7cfdd20b64c98cd83 (diff)
downloadchromium_src-85cc78c5489a2925214a02aef4baf716d74bb1cc.zip
chromium_src-85cc78c5489a2925214a02aef4baf716d74bb1cc.tar.gz
chromium_src-85cc78c5489a2925214a02aef4baf716d74bb1cc.tar.bz2
Site isolation metrics: Sniff the actual type of cross origin text/html
responses, and take access control headers into account. Also, moved the actual logic of site isolation metrics into a separate file. BUG=none TEST=none Review URL: http://codereview.chromium.org/1699028 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@46370 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/renderer/render_view.cc80
-rw-r--r--webkit/glue/site_isolation_metrics.cc176
-rw-r--r--webkit/glue/site_isolation_metrics.h39
-rw-r--r--webkit/glue/webkit_glue.gypi2
-rw-r--r--webkit/glue/weburlloader_impl.cc12
5 files changed, 238 insertions, 71 deletions
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index f6816f7..655dada 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -116,12 +116,13 @@
#include "webkit/glue/image_decoder.h"
#include "webkit/glue/media/buffered_data_source.h"
#include "webkit/glue/media/simple_data_source.h"
+#include "webkit/glue/media/video_renderer_impl.h"
#include "webkit/glue/password_form.h"
#include "webkit/glue/plugins/plugin_list.h"
#include "webkit/glue/plugins/webplugin_delegate.h"
#include "webkit/glue/plugins/webplugin_delegate_impl.h"
#include "webkit/glue/plugins/webplugin_impl.h"
-#include "webkit/glue/media/video_renderer_impl.h"
+#include "webkit/glue/site_isolation_metrics.h"
#include "webkit/glue/webdropdata.h"
#include "webkit/glue/webkit_glue.h"
#include "webkit/glue/webmediaplayer_impl.h"
@@ -145,6 +146,7 @@ using webkit_glue::FormField;
using webkit_glue::ImageResourceFetcher;
using webkit_glue::PasswordForm;
using webkit_glue::PasswordFormDomManager;
+using webkit_glue::SiteIsolationMetrics;
using WebKit::WebAccessibilityCache;
using WebKit::WebAccessibilityObject;
using WebKit::WebApplicationCacheHost;
@@ -2787,74 +2789,6 @@ void RenderView::assignIdentifierToRequest(
// Ignore
}
-// Used in logMimeTypeForCrossOriginRequest(), remove when that function
-// is removed
-typedef base::hash_map<unsigned, WebURLRequest::TargetType> TargetTypeMap;
-static TargetTypeMap target_type_map_;
-typedef base::hash_map<std::string, int> MimeTypeMap;
-static MimeTypeMap mime_type_map_;
-
-// Copied from net/base/mime_util.cc, supported_non_image_types[]
-static const char* const cross_origin_mime_types_to_log[] = {
- "text/cache-manifest",
- "text/html",
- "text/xml",
- "text/xsl",
- "text/plain",
- "text/vnd.chromium.ftp-dir",
- "text/",
- "text/css",
- "image/svg+xml",
- "application/xml",
- "application/xhtml+xml",
- "application/rss+xml",
- "application/atom+xml",
- "application/json",
- "application/x-x509-user-cert",
- "multipart/x-mixed-replace"
-};
-
-static void initMimeTypeMapIfNeeded() {
- if (!mime_type_map_.size()) {
- for (size_t i = 0; i < arraysize(cross_origin_mime_types_to_log); ++i)
- mime_type_map_[cross_origin_mime_types_to_log[i]] = i;
- }
-}
-
-static void logMimeTypeForCrossOriginRequest(
- WebFrame* frame, unsigned identifier, const WebURLResponse& response) {
- initMimeTypeMapIfNeeded();
-
- // Metrics to check the feasability of blocking cross-site requests
- // a renderer shouldn't be making (in case we try to move cross-site frames
- // into their own process someday). We're erring on the side of counting more
- // mime-types then we strictly need (we'd only consider blocking cross-site
- // requests with types similar to HTML, XML, or JSON).
- // TODO(japhet): Make these more granular. We're ignoring all miscellaneous
- // subresource requests, not just the XHRs that might be allowed.
- // Also, we should make these metrics be based on something more accurate
- // than the mime type header, such as parsing or content sniffing.
- TargetTypeMap::iterator iter = target_type_map_.find(identifier);
- if (iter != target_type_map_.end()) {
- WebURLRequest::TargetType target_type = iter->second;
- target_type_map_.erase(iter);
- if (target_type != WebURLRequest::TargetIsMainFrame
- && target_type != WebURLRequest::TargetIsSubFrame
- && target_type != WebURLRequest::TargetIsSubResource
- && target_type != WebURLRequest::TargetIsObject
- && !frame->securityOrigin().canAccess(
- WebSecurityOrigin::create(response.url()))) {
- std::string mime_type = response.mimeType().utf8();
- MimeTypeMap::iterator mime_type_iter = mime_type_map_.find(mime_type);
- if (mime_type_iter != mime_type_map_.end()) {
- UMA_HISTOGRAM_ENUMERATION(
- "SiteIsolation.CrossSiteNonFrameResponse_MIME_Type",
- mime_type_iter->second, arraysize(cross_origin_mime_types_to_log));
- }
- }
- }
-}
-
void RenderView::willSendRequest(
WebFrame* frame, unsigned identifier, WebURLRequest& request,
const WebURLResponse& redirect_response) {
@@ -2873,13 +2807,17 @@ void RenderView::willSendRequest(
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoReferrers))
request.clearHTTPHeaderField("Referer");
- target_type_map_[identifier] = request.targetType();
+ // Temporary metrics, see site_isolation_metrics.h
+ SiteIsolationMetrics::AddRequest(identifier, request.targetType());
}
void RenderView::didReceiveResponse(
WebFrame* frame, unsigned identifier, const WebURLResponse& response) {
- logMimeTypeForCrossOriginRequest(frame, identifier, response);
+ // Temporary metrics, see site_isolation_metrics.h
+ SiteIsolationMetrics::LogMimeTypeForCrossOriginRequest(frame,
+ identifier,
+ response);
// Only do this for responses that correspond to a provisional data source
// of the top-most frame. If we have a provisional data source, then we
diff --git a/webkit/glue/site_isolation_metrics.cc b/webkit/glue/site_isolation_metrics.cc
new file mode 100644
index 0000000..a97bb96
--- /dev/null
+++ b/webkit/glue/site_isolation_metrics.cc
@@ -0,0 +1,176 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "webkit/glue/site_isolation_metrics.h"
+
+#include <set>
+
+#include "base/hash_tables.h"
+#include "base/histogram.h"
+#include "net/base/mime_sniffer.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebSecurityOrigin.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebURL.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebURLResponse.h"
+
+using WebKit::WebFrame;
+using WebKit::WebSecurityOrigin;
+using WebKit::WebString;
+using WebKit::WebURL;
+using WebKit::WebURLRequest;
+using WebKit::WebURLResponse;
+
+namespace webkit_glue {
+
+typedef base::hash_map<unsigned, WebURLRequest::TargetType> TargetTypeMap;
+typedef base::hash_map<std::string, int> MimeTypeMap;
+typedef std::set<std::string> CrossOriginTextHtmlResponseSet;
+
+static TargetTypeMap* GetTargetTypeMap() {
+ static TargetTypeMap target_type_map_;
+ return &target_type_map_;
+}
+
+// Copied from net/base/mime_util.cc, supported_non_image_types[]
+static const char* const kCrossOriginMimeTypesToLog[] = {
+ "text/cache-manifest",
+ "text/html",
+ "text/xml",
+ "text/xsl",
+ "text/plain",
+ "text/vnd.chromium.ftp-dir",
+ "text/",
+ "text/css",
+ "image/svg+xml",
+ "application/xml",
+ "application/xhtml+xml",
+ "application/rss+xml",
+ "application/atom+xml",
+ "application/json",
+ "application/x-x509-user-cert",
+ "multipart/x-mixed-replace"
+};
+
+static MimeTypeMap* GetMimeTypeMap() {
+ static MimeTypeMap mime_type_map_;
+ if (!mime_type_map_.size()) {
+ for (size_t i = 0; i < arraysize(kCrossOriginMimeTypesToLog); ++i)
+ mime_type_map_[kCrossOriginMimeTypesToLog[i]] = i;
+ }
+ return &mime_type_map_;
+}
+
+// This is set is used to keep track of the response urls that we want to
+// sniff, since we will have to wait for the payload to arrive.
+static CrossOriginTextHtmlResponseSet* GetCrossOriginTextHtmlResponseSet() {
+ static CrossOriginTextHtmlResponseSet cross_origin_text_html_response_set_;
+ return &cross_origin_text_html_response_set_;
+}
+
+static void LogVerifiedTextHtmlResponse() {
+ UMA_HISTOGRAM_COUNTS(
+ "SiteIsolation.CrossSiteNonFrameResponse_verified_texthtml", 1);
+}
+
+static void LogMislabeledTextHtmlResponse() {
+ UMA_HISTOGRAM_COUNTS(
+ "SiteIsolation.CrossSiteNonFrameResponse_mislabeled_texthtml", 1);
+}
+
+void SiteIsolationMetrics::AddRequest(unsigned identifier,
+ WebURLRequest::TargetType target_type) {
+ TargetTypeMap& target_type_map = *GetTargetTypeMap();
+ target_type_map[identifier] = target_type;
+}
+
+void SiteIsolationMetrics::LogMimeTypeForCrossOriginRequest(
+ WebFrame* frame, unsigned identifier, const WebURLResponse& response) {
+ TargetTypeMap& target_type_map = *GetTargetTypeMap();
+ TargetTypeMap::iterator iter = target_type_map.find(identifier);
+ if (iter != target_type_map.end()) {
+ WebURLRequest::TargetType target_type = iter->second;
+ target_type_map.erase(iter);
+ // We want to log any cross-site request that we don't think a renderer
+ // should be allowed to make. We can safely ignore frame requests (since
+ // we'd like those to be in a separate renderer) and plugin requests, even
+ // if they are cross-origin.
+ if (target_type != WebURLRequest::TargetIsMainFrame &&
+ target_type != WebURLRequest::TargetIsSubFrame &&
+ target_type != WebURLRequest::TargetIsObject &&
+ !frame->securityOrigin().canAccess(
+ WebSecurityOrigin::create(response.url()))) {
+ std::string mime_type = response.mimeType().utf8();
+ MimeTypeMap mime_type_map = *GetMimeTypeMap();
+ MimeTypeMap::iterator mime_type_iter = mime_type_map.find(mime_type);
+ if (mime_type_iter != mime_type_map.end()) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "SiteIsolation.CrossSiteNonFrameResponse_MIME_Type",
+ mime_type_iter->second,
+ arraysize(kCrossOriginMimeTypesToLog));
+
+ // We also should check access control headers, in case this
+ // cross-origin request has been explicitly permitted.
+ // This is basically a copy of the logic of passesAccessControlCheck()
+ // in WebCore/loader/CrossOriginAccessControl.cpp.
+ WebString access_control_origin = response.httpHeaderField(
+ WebString::fromUTF8("Access-Control-Allow-Origin"));
+ if (access_control_origin != WebString::fromUTF8("*")
+ && !frame->securityOrigin().canAccess(
+ WebSecurityOrigin::createFromString(access_control_origin))) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "SiteIsolation.CrossSiteNonFrameResponse_With_CORS_MIME_Type",
+ mime_type_iter->second,
+ arraysize(kCrossOriginMimeTypesToLog));
+ }
+
+ // Sometimes resources are mislabeled as text/html. Once we have some
+ // of the payload, we want to determine if this was actually text/html.
+ if (mime_type == "text/html")
+ GetCrossOriginTextHtmlResponseSet()->insert(response.url().spec());
+ }
+ }
+ }
+}
+
+void SiteIsolationMetrics::SniffCrossOriginHTML(const WebURL& response_url,
+ const char* data,
+ int len) {
+ if (!response_url.isValid())
+ return;
+
+ CrossOriginTextHtmlResponseSet& cross_origin_text_html_response_set =
+ *GetCrossOriginTextHtmlResponseSet();
+ CrossOriginTextHtmlResponseSet::iterator request_iter =
+ cross_origin_text_html_response_set.find(response_url.spec());
+ if (request_iter != cross_origin_text_html_response_set.end()) {
+ std::string sniffed_mime_type;
+ bool successful = net::SniffMimeType(data, len, response_url,
+ "", &sniffed_mime_type);
+ if (successful && sniffed_mime_type == "text/html")
+ LogVerifiedTextHtmlResponse();
+ else
+ LogMislabeledTextHtmlResponse();
+ cross_origin_text_html_response_set.erase(request_iter);
+ }
+}
+
+void SiteIsolationMetrics::RemoveCompletedResponse(
+ const WebURL& response_url) {
+ if (!response_url.isValid())
+ return;
+
+ // Ensure we don't leave responses in the set after they've completed.
+ CrossOriginTextHtmlResponseSet& cross_origin_text_html_response_set =
+ *GetCrossOriginTextHtmlResponseSet();
+ CrossOriginTextHtmlResponseSet::iterator request_iter =
+ cross_origin_text_html_response_set.find(response_url.spec());
+ if (request_iter != cross_origin_text_html_response_set.end()) {
+ LogMislabeledTextHtmlResponse();
+ cross_origin_text_html_response_set.erase(request_iter);
+ }
+}
+
+} // namespace webkit_glue
diff --git a/webkit/glue/site_isolation_metrics.h b/webkit/glue/site_isolation_metrics.h
new file mode 100644
index 0000000..1148afb
--- /dev/null
+++ b/webkit/glue/site_isolation_metrics.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WEBKIT_GLUE_SITE_ISOLATION_METRICS_H_
+#define WEBKIT_GLUE_SITE_ISOLATION_METRICS_H_
+
+#include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h"
+
+namespace WebKit {
+class WebFrame;
+class WebURL;
+class WebURLResponse;
+}
+
+namespace webkit_glue {
+
+// Metrics to check the feasability of blocking cross-site requests
+// a renderer shouldn't be making (in case we try to move cross-site frames
+// into their own process someday). We're erring on the side of counting more
+// mime-types then we strictly need (we'd only consider blocking cross-site
+// requests with types similar to HTML, XML, or JSON).
+class SiteIsolationMetrics {
+ public:
+ static void AddRequest(unsigned identifier,
+ WebKit::WebURLRequest::TargetType target_type);
+ static void LogMimeTypeForCrossOriginRequest(
+ WebKit::WebFrame* frame,
+ unsigned identifier,
+ const WebKit::WebURLResponse& response);
+ static void SniffCrossOriginHTML(const WebKit::WebURL& response_url,
+ const char* data,
+ int len);
+ static void RemoveCompletedResponse(const WebKit::WebURL& response_url);
+};
+
+} // namespace webkit_glue
+
+#endif // WEBKIT_GLUE_SITE_ISOLATION_METRICS_H_
diff --git a/webkit/glue/webkit_glue.gypi b/webkit/glue/webkit_glue.gypi
index 00a2c81..5ea5e21 100644
--- a/webkit/glue/webkit_glue.gypi
+++ b/webkit/glue/webkit_glue.gypi
@@ -238,6 +238,8 @@
'scoped_clipboard_writer_glue.h',
'simple_webmimeregistry_impl.cc',
'simple_webmimeregistry_impl.h',
+ 'site_isolation_metrics.cc',
+ 'site_isolation_metrics.h',
'webaccessibility.cc',
'webaccessibility.h',
'webclipboard_impl.cc',
diff --git a/webkit/glue/weburlloader_impl.cc b/webkit/glue/weburlloader_impl.cc
index 710a84b..0b5697a 100644
--- a/webkit/glue/weburlloader_impl.cc
+++ b/webkit/glue/weburlloader_impl.cc
@@ -26,6 +26,7 @@
#include "webkit/glue/ftp_directory_listing_response_delegate.h"
#include "webkit/glue/multipart_response_delegate.h"
#include "webkit/glue/resource_loader_bridge.h"
+#include "webkit/glue/site_isolation_metrics.h"
#include "webkit/glue/webkit_glue.h"
using base::Time;
@@ -249,6 +250,9 @@ class WebURLLoaderImpl::Context : public base::RefCounted<Context>,
scoped_ptr<ResourceLoaderBridge> bridge_;
scoped_ptr<FtpDirectoryListingResponseDelegate> ftp_listing_delegate_;
scoped_ptr<MultipartResponseDelegate> multipart_delegate_;
+
+ // TODO(japhet): Storing this is a temporary hack for site isolation logging.
+ WebURL response_url_;
};
WebURLLoaderImpl::Context::Context(WebURLLoaderImpl* loader)
@@ -506,12 +510,17 @@ void WebURLLoaderImpl::Context::OnReceivedResponse(
ftp_listing_delegate_.reset(
new FtpDirectoryListingResponseDelegate(client_, loader_, response));
}
+
+ response_url_ = response.url();
}
void WebURLLoaderImpl::Context::OnReceivedData(const char* data, int len) {
if (!client_)
return;
+ // Temporary logging, see site_isolation_metrics.h/cc.
+ SiteIsolationMetrics::SniffCrossOriginHTML(response_url_, data, len);
+
if (ftp_listing_delegate_.get()) {
// The FTP listing delegate will make the appropriate calls to
// client_->didReceiveData and client_->didReceiveResponse.
@@ -559,6 +568,9 @@ void WebURLLoaderImpl::Context::OnCompletedRequest(
}
}
+ // Temporary logging, see site_isolation_metrics.h/cc
+ SiteIsolationMetrics::RemoveCompletedResponse(response_url_);
+
// We are done with the bridge now, and so we need to release the reference
// to ourselves that we took on behalf of the bridge. This may cause our
// destruction.