| Index: content/child/site_isolation_policy.h
|
| diff --git a/content/child/site_isolation_policy.h b/content/child/site_isolation_policy.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f2174d1f8d991c73632cbf0c342318268a49324f
|
| --- /dev/null
|
| +++ b/content/child/site_isolation_policy.h
|
| @@ -0,0 +1,225 @@
|
| +// Copyright (c) 2013 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 CONTENT_SITE_ISOLATION_POLICY_H_
|
| +#define CONTENT_SITE_ISOLATION_POLICY_H_
|
| +
|
| +#include <map>
|
| +#include <utility>
|
| +
|
| +#include "base/gtest_prod_util.h"
|
| +#include "content/common/content_export.h"
|
| +#include "third_party/WebKit/public/platform/WebURLRequest.h"
|
| +#include "third_party/WebKit/public/platform/WebURLResponse.h"
|
| +#include "third_party/WebKit/public/web/WebFrame.h"
|
| +#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
|
| +#include "webkit/child/resource_loader_bridge.h"
|
| +#include "webkit/common/resource_response_info.h"
|
| +
|
| +namespace content {
|
| +
|
| +// SiteIsolationPolicy implements the cross-site document blocking policy (XSDP)
|
| +// for Site Isolation. XSDP will monitor network responses to a renderer and
|
| +// block illegal responses so that a compromised renderer cannot steal private
|
| +// information from other sites. For now SiteIsolationPolicy monitors responses
|
| +// to gather various UMA stats to see the compatibility impact of actual
|
| +// deployment of the policy. The UMA stat categories SiteIsolationPolicy gathers
|
| +// are as follows:
|
| +//
|
| +// SiteIsolation.AllResponses : # of all network responses.
|
| +// SiteIsolation.XSD.DataLength : the length of the first packet of a response.
|
| +// SiteIsolation.XSD.MimeType (enum):
|
| +// # of responses from other sites, tagged with a document mime type.
|
| +// 0:HTML, 1:XML, 2:JSON, 3:Plain, 4:Others
|
| +// SiteIsolation.XSD.[%MIMETYPE].Blocked :
|
| +// blocked # of cross-site document responses grouped by sniffed MIME type.
|
| +// SiteIsolation.XSD.[%MIMETYPE].Blocked.RenderableStatusCode :
|
| +// # of responses with renderable status code,
|
| +// out of SiteIsolation.XSD.[%MIMETYPE].Blocked.
|
| +// SiteIsolation.XSD.[%MIMETYPE].Blocked.NonRenderableStatusCode :
|
| +// # of responses with non-renderable status code,
|
| +// out of SiteIsolation.XSD.[%MIMETYPE].Blocked.
|
| +// SiteIsolation.XSD.[%MIMETYPE].NoSniffBlocked.RenderableStatusCode :
|
| +// # of responses failed to be sniffed for its MIME type, but blocked by
|
| +// "X-Content-Type-Options: nosniff" header, and with renderable status code
|
| +// out of SiteIsolation.XSD.[%MIMETYPE].Blocked.
|
| +// SiteIsolation.XSD.[%MIMETYPE].NoSniffBlocked.NonRenderableStatusCode :
|
| +// # of responses failed to be sniffed for its MIME type, but blocked by
|
| +// "X-Content-Type-Options: nosniff" header, and with non-renderable status
|
| +// code out of SiteIsolation.XSD.[%MIMETYPE].Blocked.
|
| +// SiteIsolation.XSD.[%MIMETYPE].NotBlocked :
|
| +// # of responses, but not blocked due to failure of mime sniffing.
|
| +// SiteIsolation.XSD.[%MIMETYPE].NotBlocked.MaybeJS :
|
| +// # of responses that are plausibly sniffed to be JavaScript.
|
| +
|
| +class SiteIsolationPolicy
|
| + : public base::RefCounted<SiteIsolationPolicy>,
|
| + public webkit_glue::ResourceLoaderBridge::Peer {
|
| + public:
|
| +
|
| + SiteIsolationPolicy(
|
| + webkit_glue::ResourceLoaderBridge::Peer* original_peer,
|
| + bool policy_enforced,
|
| + GURL& frame_origin,
|
| + GURL& request_url,
|
| + int request_id,
|
| + ResourceType::Type resource_type);
|
| +
|
| + // ResourceLoaderBridge::Peer methods: we directly calls original_peer_'s
|
| + // corresponding member functions other than OnReceiveRedirect(),
|
| + // OnReceivedResponse(), OnReceivedData(), and OnCompletedRequest().
|
| + virtual void OnUploadProgress(uint64 position, uint64 size) OVERRIDE;
|
| + virtual void OnDownloadedData(int len) OVERRIDE;
|
| + virtual void OnReceivedCachedMetadata(const char* data, int len) OVERRIDE;
|
| + virtual void OnCompletedRequest(
|
| + int error_code,
|
| + bool was_ignored_by_handler,
|
| + const std::string& security_info,
|
| + const base::TimeTicks& completion_time) OVERRIDE;
|
| +
|
| + // Updates the request_url_ to |new_url| when the request this peer is
|
| + // listening to is redirected.
|
| + virtual bool OnReceivedRedirect(
|
| + const GURL& new_url,
|
| + const webkit_glue::ResourceResponseInfo& info,
|
| + bool* has_new_first_party_for_cookies,
|
| + GURL* new_first_party_for_cookies) OVERRIDE;
|
| +
|
| + // Records the HTTP header information of the response. We use the recorded
|
| + // header information to decide if this response will be the subject of
|
| + // cross-site document blocking. If it is, cross_site_document_header_ is set
|
| + // to true. This also makes state_ proceed from INIT to RESPONSE_RECEIVED.
|
| + virtual void OnReceivedResponse(
|
| + const webkit_glue::ResourceResponseInfo& info) OVERRIDE;
|
| +
|
| + // Examines the first network packet to see whether this response should be
|
| + // blocked by our cross-site document policy. This only examines response data
|
| + // when cross_site_document_header_ is true by OnReceivedResponse(). We apply
|
| + // content-sniffing to the first network packet to decide to block the
|
| + // response and records various kinds of UMA data stats at the same time.
|
| + // TODO(dsjang): Here is where we can do actual blocking of the body of a
|
| + // response. When the body is blocked, we can return an empty string instead.
|
| + virtual void OnReceivedData(const char* data,
|
| + int data_length,
|
| + int encoded_data_length) OVERRIDE;
|
| +
|
| + webkit_glue::ResourceLoaderBridge::Peer* get_wrapped_peer() {
|
| + return original_peer_;
|
| + }
|
| +
|
| + void set_wrapped_peer(webkit_glue::ResourceLoaderBridge::Peer* peer) {
|
| + original_peer_ = peer;
|
| + }
|
| +
|
| +private:
|
| + FRIEND_TEST_ALL_PREFIXES(SiteIsolationPolicyTest, IsBlockableScheme);
|
| + FRIEND_TEST_ALL_PREFIXES(SiteIsolationPolicyTest, IsSameSite);
|
| + FRIEND_TEST_ALL_PREFIXES(SiteIsolationPolicyTest, IsValidCorsHeaderSet);
|
| + FRIEND_TEST_ALL_PREFIXES(SiteIsolationPolicyTest, SniffForHTML);
|
| + FRIEND_TEST_ALL_PREFIXES(SiteIsolationPolicyTest, SniffForXML);
|
| + FRIEND_TEST_ALL_PREFIXES(SiteIsolationPolicyTest, SniffForJSON);
|
| + FRIEND_TEST_ALL_PREFIXES(SiteIsolationPolicyTest, SniffForJS);
|
| +
|
| + enum CanonicalMimeType {
|
| + HTML = 0,
|
| + XML = 1,
|
| + JSON = 2,
|
| + Plain = 3,
|
| + Others = 4,
|
| + MaxCanonicalMimeType,
|
| + };
|
| +
|
| + enum RequestProgressState {
|
| + INIT = 0,
|
| + RESPONSE_RECEIVED = 1,
|
| + DATA_RECEIVED = 2,
|
| + COMPLETED = 3,
|
| + };
|
| +
|
| + // Returns the representative mime type enum value of the mime type of
|
| + // response. For example, this returns the same value for all text/xml mime
|
| + // type families such as application/xml, application/rss+xml.
|
| + static CanonicalMimeType GetCanonicalMimeType(
|
| + const std::string& mime_type);
|
| +
|
| + // Returns whether this scheme is a target of cross-site document
|
| + // policy(XSDP). This returns true only for http://* and https://* urls.
|
| + static bool IsBlockableScheme(const GURL& frame_origin);
|
| +
|
| + // Returns whether the two urls belong to the same sites.
|
| + static bool IsSameSite(const GURL& frame_origin, const GURL& response_url);
|
| +
|
| + // Returns whether there's a valid CORS header for frame_origin. This is
|
| + // simliar to CrossOriginAccessControl::passesAccessControlCheck(), but we use
|
| + // sites as our security domain, not origins. TODO(dsjang): this must be
|
| + // improved to be more accurate to the actual CORS specification. For now,
|
| + // this works conservatively, allowing XSDs that are not allowed by actual
|
| + // CORS rules by ignoring 1) credentials and 2) methods. Preflight requests
|
| + // don't matter here since they are not used to decide whether to block a
|
| + // document or not on the client side.
|
| + static bool IsValidCorsHeaderSet(GURL& frame_origin,
|
| + GURL& website_origin,
|
| + std::string access_control_origin);
|
| +
|
| + static bool SniffForHTML(const char* data, size_t length);
|
| + static bool SniffForXML(const char* data, size_t length);
|
| + static bool SniffForJSON(const char* data, size_t length);
|
| +
|
| + static bool MatchesSignature(const char* data,
|
| + size_t length,
|
| + const char* signatures[],
|
| + size_t arr_size);
|
| +
|
| + // TODO(dsjang): this is only needed for collecting UMA stat. Will be deleted
|
| + // when this class is used for actual blocking.
|
| + static bool SniffForJS(const char* data, size_t length);
|
| +
|
| + // TODO(dsjang): this is only needed for collecting UMA stat. Will be deleted
|
| + // when this class is used for actual blocking.
|
| + static bool IsRenderableStatusCodeForDocument(int status_code);
|
| +
|
| + friend class base::RefCounted<SiteIsolationPolicy>;
|
| + virtual ~SiteIsolationPolicy() {}
|
| +
|
| + // This class wraps original_peer_ to intercept certain calls of it to monitor
|
| + // the lifetime of a request to apply our cross-site document blocking.
|
| + webkit_glue::ResourceLoaderBridge::Peer* original_peer_;
|
| +
|
| + // These are fixed when the object is created. Flag that decides that we
|
| + // actually block a response by enforcing the cross-site document policy.
|
| + bool policy_enforced_;
|
| + GURL frame_origin_;
|
| + // However, request_url_ is updated to a new url when redirected.
|
| + GURL request_url_;
|
| + int request_id_;
|
| + ResourceType::Type resource_type_;
|
| +
|
| + // The current state of the request. This can only proceeds to a greater value
|
| + // when an event happens. This is only used for sanity checks in DCHECK() to
|
| + // see if callbacks are called in an expected order.
|
| + RequestProgressState state_;
|
| +
|
| + // This is set to true when we decide that the response is a target of our
|
| + // cross-site document blocking policy, decided when the headers are deceived
|
| + // by OnReceivedResponse().
|
| + bool cross_site_document_header_;
|
| +
|
| + // The following 3 member variables are only valid after OnReceivedResponse()
|
| + // is called (after RESPONSE_RECEIVED). This must be the same as request_url_
|
| + // since request_url_ is updated whenever the request is redirected.
|
| + CanonicalMimeType canonical_mime_type_;
|
| + int http_status_code_;
|
| + bool no_sniff_;
|
| +
|
| + // This is initially false, but becomes true after we confirm that this is
|
| + // safe under our cross-site document policy by applying content sniffing to
|
| + // the first network packet from the response.
|
| + bool confirmed_safe_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(SiteIsolationPolicy);
|
| +};
|
| +
|
| +} // namespace content
|
| +
|
| +#endif // CONTENT_SITE_ISOLATION_POLICY_H_
|
|
|