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