1 // Copyright 2019 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_BASE_NETWORK_ISOLATION_KEY_H_ 6 #define NET_BASE_NETWORK_ISOLATION_KEY_H_ 7 8 #include <optional> 9 #include <string> 10 11 #include "base/types/pass_key.h" 12 #include "base/unguessable_token.h" 13 #include "net/base/net_export.h" 14 #include "net/base/schemeful_site.h" 15 16 namespace url { 17 class Origin; 18 } 19 20 namespace network::mojom { 21 class NonEmptyNetworkIsolationKeyDataView; 22 } 23 24 namespace net { 25 class CookiePartitionKey; 26 class NetworkAnonymizationKey; 27 } 28 29 namespace net { 30 31 // Key used to isolate shared network stack resources used by requests based on 32 // the context on which they were made. 33 class NET_EXPORT NetworkIsolationKey { 34 public: 35 // Full constructor. When a request is initiated by the top frame, it must 36 // also populate the |frame_site| parameter when calling this constructor. 37 NetworkIsolationKey( 38 const SchemefulSite& top_frame_site, 39 const SchemefulSite& frame_site, 40 const std::optional<base::UnguessableToken>& nonce = std::nullopt); 41 42 // Alternative constructor that takes ownership of arguments, to save copies. 43 NetworkIsolationKey( 44 SchemefulSite&& top_frame_site, 45 SchemefulSite&& frame_site, 46 std::optional<base::UnguessableToken>&& nonce = std::nullopt); 47 48 // Legacy constructor. 49 // TODO(https://crbug.com/1145294): Remove this in favor of above 50 // constructor. 51 NetworkIsolationKey(const url::Origin& top_frame_origin, 52 const url::Origin& frame_origin); 53 54 // Construct an empty key. 55 NetworkIsolationKey(); 56 57 NetworkIsolationKey(const NetworkIsolationKey& network_isolation_key); 58 NetworkIsolationKey(NetworkIsolationKey&& network_isolation_key); 59 60 ~NetworkIsolationKey(); 61 62 NetworkIsolationKey& operator=( 63 const NetworkIsolationKey& network_isolation_key); 64 NetworkIsolationKey& operator=(NetworkIsolationKey&& network_isolation_key); 65 66 // Creates a transient non-empty NetworkIsolationKey by creating an opaque 67 // origin. This prevents the NetworkIsolationKey from sharing data with other 68 // NetworkIsolationKeys. Data for transient NetworkIsolationKeys is not 69 // persisted to disk. 70 static NetworkIsolationKey CreateTransientForTesting(); 71 72 // Creates a new key using |top_frame_site_| and |new_frame_site|. 73 NetworkIsolationKey CreateWithNewFrameSite( 74 const SchemefulSite& new_frame_site) const; 75 76 // Compare keys for equality, true if all enabled fields are equal. 77 bool operator==(const NetworkIsolationKey& other) const { 78 switch (GetMode()) { 79 case Mode::kFrameSiteWithSharedOpaqueEnabled: 80 if ((frame_site_ && frame_site_->opaque()) && 81 (other.frame_site_ && other.frame_site_->opaque())) { 82 return std::tie(top_frame_site_, nonce_) == 83 std::tie(other.top_frame_site_, other.nonce_); 84 } 85 [[fallthrough]]; 86 case Mode::kFrameSiteEnabled: 87 return std::tie(top_frame_site_, frame_site_, nonce_) == 88 std::tie(other.top_frame_site_, other.frame_site_, other.nonce_); 89 case Mode::kCrossSiteFlagEnabled: 90 return std::tie(top_frame_site_, is_cross_site_, nonce_) == 91 std::tie(other.top_frame_site_, other.is_cross_site_, 92 other.nonce_); 93 } 94 } 95 96 // Compare keys for inequality, true if any enabled field varies. 97 bool operator!=(const NetworkIsolationKey& other) const { 98 return !(*this == other); 99 } 100 101 // Provide an ordering for keys based on all enabled fields. 102 bool operator<(const NetworkIsolationKey& other) const { 103 switch (GetMode()) { 104 case Mode::kFrameSiteWithSharedOpaqueEnabled: 105 if ((frame_site_ && frame_site_->opaque()) && 106 (other.frame_site_ && other.frame_site_->opaque())) { 107 return std::tie(top_frame_site_, nonce_) < 108 std::tie(other.top_frame_site_, other.nonce_); 109 } 110 [[fallthrough]]; 111 case Mode::kFrameSiteEnabled: 112 return std::tie(top_frame_site_, frame_site_, nonce_) < 113 std::tie(other.top_frame_site_, other.frame_site_, other.nonce_); 114 case Mode::kCrossSiteFlagEnabled: 115 return std::tie(top_frame_site_, is_cross_site_, nonce_) < 116 std::tie(other.top_frame_site_, other.is_cross_site_, 117 other.nonce_); 118 } 119 } 120 121 // Returns the string representation of the key for use in string-keyed disk 122 // cache. This is the string representation of each piece of the key separated 123 // by spaces. Returns nullopt if the network isolation key is transient, in 124 // which case, nothing should typically be saved to disk using the key. 125 std::optional<std::string> ToCacheKeyString() const; 126 127 // Returns string for debugging. Difference from ToString() is that transient 128 // entries may be distinguishable from each other. 129 std::string ToDebugString() const; 130 131 // Returns true if all parts of the key are non-empty. 132 bool IsFullyPopulated() const; 133 134 // Returns true if this key's lifetime is short-lived, or if 135 // IsFullyPopulated() returns true. It may not make sense to persist state to 136 // disk related to it (e.g., disk cache). 137 bool IsTransient() const; 138 139 // Getters for the top frame and frame sites. These accessors are primarily 140 // intended for IPC calls, and to be able to create an IsolationInfo from a 141 // NetworkIsolationKey. GetTopFrameSite()142 const std::optional<SchemefulSite>& GetTopFrameSite() const { 143 return top_frame_site_; 144 } 145 146 enum class Mode { 147 // This scheme indicates that "triple-key" NetworkIsolationKeys are used to 148 // partition the HTTP cache. This key will have the following properties: 149 // `top_frame_site` -> the schemeful site of the top level page. 150 // `frame_site ` -> the schemeful site of the frame. 151 // `is_cross_site` -> std::nullopt. 152 kFrameSiteEnabled, 153 // This scheme indicates that "2.5-key" NetworkIsolationKeys are used to 154 // partition the HTTP cache. This key will have the following properties: 155 // `top_frame_site_` -> the schemeful site of the top level page. 156 // `frame_site_` -> should only be accessed for serialization or building 157 // nonced CookiePartitionKeys. 158 // `is_cross_site_` -> a boolean indicating whether the frame site is 159 // schemefully cross-site from the top-level site. 160 kCrossSiteFlagEnabled, 161 // This scheme indicates that "triple-key" NetworkIsolationKeys are used to 162 // partition the HTTP cache except when the frame site has an opaque origin. 163 // In that case, a fixed value will be used instead of the frame site such 164 // that all opaque origin frames under a given top-level site share a cache 165 // partition (unless the NIK is explicitly provided a nonce). 166 kFrameSiteWithSharedOpaqueEnabled, 167 }; 168 169 // Returns the cache key scheme currently in use. 170 static Mode GetMode(); 171 172 // Do not use outside of testing. Returns the `frame_site_`. GetFrameSiteForTesting()173 const std::optional<SchemefulSite> GetFrameSiteForTesting() const { 174 if (GetMode() == Mode::kFrameSiteEnabled || 175 GetMode() == Mode::kFrameSiteWithSharedOpaqueEnabled) { 176 return frame_site_; 177 } 178 return std::nullopt; 179 } 180 181 // Do not use outside of testing. Returns `is_cross_site_`. GetIsCrossSiteForTesting()182 const std::optional<bool> GetIsCrossSiteForTesting() const { 183 if (GetMode() == Mode::kCrossSiteFlagEnabled) { 184 return is_cross_site_; 185 } 186 return std::nullopt; 187 } 188 189 // When serializing a NIK for sending via mojo we want to access the frame 190 // site directly. We don't want to expose this broadly, though, hence the 191 // passkey. 192 using SerializationPassKey = base::PassKey<struct mojo::StructTraits< 193 network::mojom::NonEmptyNetworkIsolationKeyDataView, 194 NetworkIsolationKey>>; GetFrameSiteForSerialization(SerializationPassKey)195 const std::optional<SchemefulSite>& GetFrameSiteForSerialization( 196 SerializationPassKey) const { 197 CHECK(!IsEmpty()); 198 return frame_site_; 199 } 200 // We also need to access the frame site directly when constructing 201 // CookiePartitionKey for nonced partitions. We also use a passkey for this 202 // case. 203 using CookiePartitionKeyPassKey = base::PassKey<CookiePartitionKey>; GetFrameSiteForCookiePartitionKey(CookiePartitionKeyPassKey)204 const std::optional<SchemefulSite>& GetFrameSiteForCookiePartitionKey( 205 CookiePartitionKeyPassKey) const { 206 CHECK(!IsEmpty()); 207 return frame_site_; 208 } 209 // Same as above but for constructing a `NetworkAnonymizationKey()` from this 210 // NIK. 211 using NetworkAnonymizationKeyPassKey = base::PassKey<NetworkAnonymizationKey>; GetFrameSiteForNetworkAnonymizationKey(NetworkAnonymizationKeyPassKey)212 const std::optional<SchemefulSite>& GetFrameSiteForNetworkAnonymizationKey( 213 NetworkAnonymizationKeyPassKey) const { 214 CHECK(!IsEmpty()); 215 return frame_site_; 216 } 217 218 // Getter for the nonce. GetNonce()219 const std::optional<base::UnguessableToken>& GetNonce() const { 220 return nonce_; 221 } 222 223 // Returns true if all parts of the key are empty. 224 bool IsEmpty() const; 225 226 private: 227 // Whether this key has opaque origins or a nonce. 228 bool IsOpaque() const; 229 230 // The origin/etld+1 of the top frame of the page making the request. 231 std::optional<SchemefulSite> top_frame_site_; 232 233 // The origin/etld+1 of the frame that initiates the request. 234 std::optional<SchemefulSite> frame_site_; 235 236 // A boolean indicating whether the frame origin is cross-site from the 237 // top-level origin. This will be used for experiments to determine the 238 // the difference in performance between partitioning the HTTP cache using the 239 // top-level origin and frame origin ("triple-keying") vs. the top-level 240 // origin and an is-cross-site bit ("2.5-keying") like the 241 // `NetworkAnonymizationKey` uses for network state partitioning. This will be 242 // std::nullopt when `GetMode()` returns `Mode::kFrameSiteEnabled` or 243 // `Mode::kFrameSiteWithSharedOpaqueEnabled`, or for an empty 244 // `NetworkIsolationKey`. 245 std::optional<bool> is_cross_site_; 246 247 // Having a nonce is a way to force a transient opaque `NetworkIsolationKey` 248 // for non-opaque origins. 249 std::optional<base::UnguessableToken> nonce_; 250 }; 251 252 } // namespace net 253 254 #endif // NET_BASE_NETWORK_ISOLATION_KEY_H_ 255