// Copyright 2020 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 NET_BASE_ISOLATION_INFO_H_ #define NET_BASE_ISOLATION_INFO_H_ #include #include #include "base/unguessable_token.h" #include "net/base/net_export.h" #include "net/base/network_isolation_key.h" #include "net/cookies/site_for_cookies.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "url/origin.h" namespace network::mojom { class IsolationInfoDataView; } // namespace network::mojom namespace mojo { template struct StructTraits; } // namespace mojo namespace net { // Class to store information about network stack requests based on the context // in which they are made. It provides NetworkIsolationKeys, used to shard // storage, and SiteForCookies, used determine when to send same site cookies. // The IsolationInfo is typically the same for all subresource requests made in // the context of the same frame, but may be different for different frames // within a page. The IsolationInfo associated with requests for frames may // change as redirects are followed, and this class also contains the logic on // how to do that. // // The SiteForCookies logic in this class is currently unused, but will // eventually replace the logic in URLRequest/RedirectInfo for tracking and // updating that value. class NET_EXPORT IsolationInfo { public: // The update-on-redirect patterns. // // In general, almost everything should use kOther, as a // kMainFrame request accidentally sent or redirected to an attacker // allows cross-site tracking, and kSubFrame allows information // leaks between sites that iframe each other. Anything that uses // kMainFrame should be user triggered and user visible, like a main // frame navigation or downloads. // // The RequestType is a core part of an IsolationInfo, and using an // IsolationInfo with one value to create an IsolationInfo with another // RequestType is generally not a good idea, unless the RequestType of the // new IsolationInfo is kOther. enum class RequestType { // Updates top level origin, frame origin, and SiteForCookies on redirect. // These requests allow users to be recognized across sites on redirect, so // should not generally be used for anything other than navigations. kMainFrame, // Only updates frame origin on redirect. kSubFrame, // Updates nothing on redirect. kOther, }; // Bound the party_context size with a reasonable number. static constexpr size_t kPartyContextMaxSize = 20; // Default constructor returns an IsolationInfo with empty origins, a null // SiteForCookies(), null |party_context|, and a RequestType of kOther. IsolationInfo(); IsolationInfo(const IsolationInfo&); IsolationInfo(IsolationInfo&&); ~IsolationInfo(); IsolationInfo& operator=(const IsolationInfo&); IsolationInfo& operator=(IsolationInfo&&); // Simple constructor for internal requests. Sets |frame_origin| and // |site_for_cookies| match |top_frame_origin|. Sets |request_type| to // kOther. Will only send SameSite cookies to the site associated with // the passed in origin. |party_context| is set to be an empty set. static IsolationInfo CreateForInternalRequest( const url::Origin& top_frame_origin); // Creates a transient IsolationInfo. A transient IsolationInfo will not save // data to disk and not send SameSite cookies. Equivalent to calling // CreateForInternalRequest with a fresh opaque origin. static IsolationInfo CreateTransient(); // Creates an IsolationInfo from the serialized contents. Returns a nullopt // if deserialization fails or if data is inconsistent. static absl::optional Deserialize( const std::string& serialized); // Creates an IsolationInfo with the provided parameters. If the parameters // are inconsistent, DCHECKs. In particular: // * If |request_type| is kMainFrame, |top_frame_origin| must equal // |frame_origin|, and |site_for_cookies| must be either null or first party // with respect to them. // * If |request_type| is kSubFrame, |top_frame_origin| must be // first party with respect to |site_for_cookies|, or |site_for_cookies| // must be null. // * If |request_type| is kOther, |top_frame_origin| and // |frame_origin| must be first party with respect to |site_for_cookies|, or // |site_for_cookies| must be null. // * If |party_context| is not empty, |top_frame_origin| must not be null. // * If |nonce| is specified, then |top_frame_origin| must not be null. // // Note that the |site_for_cookies| consistency checks are skipped when // |site_for_cookies| is not HTTP/HTTPS. static IsolationInfo Create( RequestType request_type, const url::Origin& top_frame_origin, const url::Origin& frame_origin, const SiteForCookies& site_for_cookies, absl::optional> party_context = absl::nullopt, const base::UnguessableToken* nonce = nullptr); // Create and IsolationInfo from the context of a double key. This should only // be used when we don't have access to the frame_origin because the // IsolationInfo is being created from an existing double keyed IsolationInfo. static IsolationInfo CreateDoubleKey( RequestType request_type, const url::Origin& top_frame_origin, const SiteForCookies& site_for_cookies, absl::optional> party_context = absl::nullopt, const base::UnguessableToken* nonce = nullptr); // Create an IsolationInfos that may not be fully correct - in particular, // the SiteForCookies will always set to null, and if the NetworkIsolationKey // only has a top frame origin, the frame origin will either be set to the top // frame origin, in the kMainFrame case, or be replaced by an opaque // origin in all other cases. If the NetworkIsolationKey is not fully // populated, will create an empty IsolationInfo. This is intended for use // while transitioning from NIKs being set on only some requests to // IsolationInfos being set on all requests. static IsolationInfo CreatePartial( RequestType request_type, const net::NetworkIsolationKey& network_isolation_key); // Returns nullopt if the arguments are not consistent. Otherwise, returns a // fully populated IsolationInfo. Any IsolationInfo that can be created by // the other construction methods, including the 0-argument constructor, is // considered consistent. // // Intended for use by cross-process deserialization. static absl::optional CreateIfConsistent( RequestType request_type, const absl::optional& top_frame_origin, const absl::optional& frame_origin, const SiteForCookies& site_for_cookies, absl::optional> party_context = absl::nullopt, const base::UnguessableToken* nonce = nullptr); // Create a new IsolationInfo for a redirect to the supplied origin. |this| is // unmodified. IsolationInfo CreateForRedirect(const url::Origin& new_origin) const; // Intended for temporary use in locations that should be using main frame and // frame origin, but are currently only using frame origin, because the // creating object may be shared across main frame objects. Having a special // constructor for these methods makes it easier to keep track of locating // callsites that need to have their IsolationInfo filled in. static IsolationInfo ToDoUseTopFrameOriginAsWell( const url::Origin& incorrectly_used_frame_origin); RequestType request_type() const { return request_type_; } bool IsEmpty() const { return !top_frame_origin_; } // These may only be nullopt if created by the empty constructor. If one is // nullopt, both are, and SiteForCookies is null. // // Note that these are the values the IsolationInfo was created with. In the // case an IsolationInfo was created from a NetworkIsolationKey, they may be // scheme + eTLD+1 instead of actual origins. const absl::optional& top_frame_origin() const { return top_frame_origin_; } const absl::optional& frame_origin() const; const NetworkIsolationKey& network_isolation_key() const { return network_isolation_key_; } const absl::optional& nonce() const { return nonce_; } // The value that should be consulted for the third-party cookie blocking // policy, as defined in Section 2.1.1 and 2.1.2 of // https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site. // // WARNING: This value must only be used for the third-party cookie blocking // policy. It MUST NEVER be used for any kind of SECURITY check. const SiteForCookies& site_for_cookies() const { return site_for_cookies_; } // Return |party_context| which exclude the top frame origin and the frame // origin. // TODO(mmenke): Make this function PartyContextForTesting() after switching // RenderFrameHostImpl to use the parent IsolationInfo to create the child // IsolationInfo instead of walking through all parent frames. const absl::optional>& party_context() const { return party_context_; } bool IsEqualForTesting(const IsolationInfo& other) const; // Serialize the `IsolationInfo` into a string. Fails if transient, returning // an empty string. std::string Serialize() const; // Returns true if the IsolationInfo has a triple keyed scheme. This // means both `frame_site_` and `top_frame_site_` are populated. static bool IsFrameSiteEnabled(); private: IsolationInfo(RequestType request_type, const absl::optional& top_frame_origin, const absl::optional& frame_origin, const SiteForCookies& site_for_cookies, const base::UnguessableToken* nonce, absl::optional> party_context); RequestType request_type_; absl::optional top_frame_origin_; absl::optional frame_origin_; // This can be deduced from the two origins above, but keep a cached version // to avoid repeated eTLD+1 calculations, when this is using eTLD+1. net::NetworkIsolationKey network_isolation_key_; SiteForCookies site_for_cookies_; // Having a nonce is a way to force a transient opaque `IsolationInfo` // for non-opaque origins. absl::optional nonce_; // This will hold the list of distinct sites in the form of SchemefulSite to // be used for First-Party-Sets check. // // For |request_type_| being either RequestType::kMainFrame or // RequestType::kSubFrame, |party_context| holds the set of the sites // of the frames in between the current frame and the top frame (i.e. not // considering the current frame or the top frame). // // For |request_type_| being RequestType::kOther, |party_context_| holds the // above, and also the site of the current frame. // // Note that if an intermediate frame shares a site with the top frame, that // frame's site is not reflected in the |party_context_|. Also note that if an // intermediate frame shares a site with the current frame, that frame's site // is still included in the set. The top frame's site is excluded because it // is redundant with the |top_frame_origin_| field. The current frame is // excluded to make it easier to update on subframe redirects. absl::optional> party_context_; // Mojo serialization code needs to access internal party_context_ field. friend struct mojo::StructTraits; }; } // namespace net #endif // NET_BASE_ISOLATION_INFO_H_