summaryrefslogtreecommitdiff
path: root/chromium/net/base/isolation_info.h
blob: 2a5e3946e49a64ee6ac389aeda68aaffbc3cb491 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
// 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 <set>
#include <string>

#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 <typename DataViewType, typename T>
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<IsolationInfo> 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<std::set<SchemefulSite>> 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<std::set<SchemefulSite>> 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<IsolationInfo> CreateIfConsistent(
      RequestType request_type,
      const absl::optional<url::Origin>& top_frame_origin,
      const absl::optional<url::Origin>& frame_origin,
      const SiteForCookies& site_for_cookies,
      absl::optional<std::set<SchemefulSite>> 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<url::Origin>& top_frame_origin() const {
    return top_frame_origin_;
  }
  const absl::optional<url::Origin>& frame_origin() const;

  const NetworkIsolationKey& network_isolation_key() const {
    return network_isolation_key_;
  }

  const absl::optional<base::UnguessableToken>& 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<std::set<SchemefulSite>>& 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<url::Origin>& top_frame_origin,
                const absl::optional<url::Origin>& frame_origin,
                const SiteForCookies& site_for_cookies,
                const base::UnguessableToken* nonce,
                absl::optional<std::set<SchemefulSite>> party_context);

  RequestType request_type_;

  absl::optional<url::Origin> top_frame_origin_;
  absl::optional<url::Origin> 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<base::UnguessableToken> 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<std::set<SchemefulSite>> party_context_;

  // Mojo serialization code needs to access internal party_context_ field.
  friend struct mojo::StructTraits<network::mojom::IsolationInfoDataView,
                                   IsolationInfo>;
};

}  // namespace net

#endif  // NET_BASE_ISOLATION_INFO_H_