• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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