summaryrefslogtreecommitdiff
path: root/chromium/net/cookies/cookie_inclusion_status.h
blob: 9e506b555012b3cd354e953e9fadb7faa3a46564 (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
269
270
271
272
273
274
275
276
277
278
279
// 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_COOKIES_COOKIE_INCLUSION_STATUS_H_
#define NET_COOKIES_COOKIE_INCLUSION_STATUS_H_

#include <string>
#include <vector>

#include "net/base/net_export.h"

class GURL;

namespace net {

// This class represents if a cookie was included or excluded in a cookie get or
// set operation, and if excluded why. It holds a vector of reasons for
// exclusion, where cookie inclusion is represented by the absence of any
// exclusion reasons. Also marks whether a cookie should be warned about, e.g.
// for deprecation or intervention reasons.
class NET_EXPORT CookieInclusionStatus {
 public:
  // Types of reasons why a cookie might be excluded.
  // If adding a ExclusionReason, please also update the GetDebugString()
  // method.
  enum ExclusionReason {
    EXCLUDE_UNKNOWN_ERROR = 0,

    EXCLUDE_HTTP_ONLY = 1,
    EXCLUDE_SECURE_ONLY = 2,
    EXCLUDE_DOMAIN_MISMATCH = 3,
    EXCLUDE_NOT_ON_PATH = 4,
    EXCLUDE_SAMESITE_STRICT = 5,
    EXCLUDE_SAMESITE_LAX = 6,

    // The following two are used for the SameSiteByDefaultCookies experiment,
    // where if the SameSite attribute is not specified, it will be treated as
    // SameSite=Lax by default.
    EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX = 7,
    // This is used if SameSite=None is specified, but the cookie is not
    // Secure.
    EXCLUDE_SAMESITE_NONE_INSECURE = 8,
    EXCLUDE_USER_PREFERENCES = 9,

    // Statuses specific to setting cookies
    EXCLUDE_FAILURE_TO_STORE = 10,
    EXCLUDE_NONCOOKIEABLE_SCHEME = 11,
    EXCLUDE_OVERWRITE_SECURE = 12,
    EXCLUDE_OVERWRITE_HTTP_ONLY = 13,
    EXCLUDE_INVALID_DOMAIN = 14,
    EXCLUDE_INVALID_PREFIX = 15,

    // This should be kept last.
    NUM_EXCLUSION_REASONS
  };

  // Reason to warn about a cookie. Any information contained in WarningReason
  // of an included cookie may be passed to an untrusted renderer.
  // If you add one, please update GetDebugString().
  enum WarningReason {
    // Of the following 3 SameSite warnings, there will be, at most, a single
    // active one.

    // Warn if a cookie with unspecified SameSite attribute is used in a
    // cross-site context.
    WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT = 0,
    // Warn if a cookie with SameSite=None is not Secure.
    WARN_SAMESITE_NONE_INSECURE = 1,
    // Warn if a cookie with unspecified SameSite attribute is defaulted into
    // Lax and is sent on a request with unsafe method, only because it is new
    // enough to activate the Lax-allow-unsafe intervention.
    WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE = 2,

    // The following warnings indicate that an included cookie with an effective
    // SameSite is experiencing a SameSiteCookieContext::|context| ->
    // SameSiteCookieContext::|schemeful_context| downgrade that will prevent
    // its access schemefully.
    // This situation means that a cookie is accessible when the
    // SchemefulSameSite feature is disabled but not when it's enabled,
    // indicating changed behavior and potential breakage.
    //
    // For example, a Strict to Lax downgrade for an effective SameSite=Strict
    // cookie:
    // This cookie would be accessible in the Strict context as its SameSite
    // value is Strict. However its context for schemeful same-site becomes Lax.
    // A strict cookie cannot be accessed in a Lax context and therefore the
    // behavior has changed.
    // As a counterexample, a Strict to Lax downgrade for an effective
    // SameSite=Lax cookie: A Lax cookie can be accessed in both Strict and Lax
    // contexts so there is no behavior change (and we don't warn about it).
    //
    // The warnings are in the following format:
    // WARN_{context}_{schemeful_context}_DOWNGRADE_{samesite_value}_SAMESITE
    //
    // Of the following 5 SameSite warnings, there will be, at most, a single
    // active one.

    // Strict to Lax downgrade for an effective SameSite=Strict cookie.
    // This warning is only applicable for cookies being sent because a Strict
    // cookie will be set in both Strict and Lax Contexts so the downgrade will
    // not affect it.
    WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE = 3,
    // Strict to Cross-site downgrade for an effective SameSite=Strict cookie.
    // This also applies to Strict to Lax Unsafe downgrades due to Lax Unsafe
    // behaving like Cross-site.
    WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE = 4,
    // Strict to Cross-site downgrade for an effective SameSite=Lax cookie.
    // This also applies to Strict to Lax Unsafe downgrades due to Lax Unsafe
    // behaving like Cross-site.
    WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE = 5,
    // Lax to Cross-site downgrade for an effective SameSite=Strict cookie.
    // This warning is only applicable for cookies being set because a Strict
    // cookie will not be sent in a Lax context so the downgrade would not
    // affect it.
    WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE = 6,
    // Lax to Cross-site downgrade for an effective SameSite=Lax cookie.
    WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE = 7,

    // This is applied to a cookie that may be part of a "double cookie" pair
    // used for compatibility reasons. These pairs consist of one cookie that
    // has "SameSite=None; Secure" and a duplicate cookie that leaves SameSite
    // unspecified to maintain compatibility with browsers that do not support
    // the "SameSite=None" attribute. This warning is applied to both
    // members of the pair. See cookie_util::IsSameSiteCompatPair().
    //
    // If computing this for a cookie access attempt from a non-network context
    // (i.e. script), this should not be applied if either member of the pair is
    // HttpOnly, to avoid leaking information about the name and value of
    // HttpOnly cookies to an untrusted renderer.
    //
    // This is only relevant if WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT is
    // present on the same status or a status for a cookie accessed at the same
    // time, so it may not be applied at other times (e.g. when the context is
    // same-site).
    WARN_SAMESITE_COMPAT_PAIR = 8,

    // This should be kept last.
    NUM_WARNING_REASONS
  };

  // These enums encode the context downgrade warnings + the secureness of the
  // url sending/setting the cookie. They're used for metrics only. The format
  // is {context}_{schemeful_context}_{samesite_value}_{securness}.
  // NO_DOWNGRADE_{securness} indicates that a cookie didn't have a breaking
  // context downgrade and was A) included B) excluded only due to insufficient
  // same-site context. I.e. the cookie wasn't excluded due to other reasons
  // such as third-party cookie blocking. Keep this in line with
  // SameSiteCookieContextBreakingDowngradeWithSecureness in enums.xml.
  enum ContextDowngradeMetricValues {
    NO_DOWNGRADE_INSECURE = 0,
    NO_DOWNGRADE_SECURE = 1,

    STRICT_LAX_STRICT_INSECURE = 2,
    STRICT_CROSS_STRICT_INSECURE = 3,
    STRICT_CROSS_LAX_INSECURE = 4,
    LAX_CROSS_STRICT_INSECURE = 5,
    LAX_CROSS_LAX_INSECURE = 6,

    STRICT_LAX_STRICT_SECURE = 7,
    STRICT_CROSS_STRICT_SECURE = 8,
    STRICT_CROSS_LAX_SECURE = 9,
    LAX_CROSS_STRICT_SECURE = 10,
    LAX_CROSS_LAX_SECURE = 11,

    // Keep last.
    kMaxValue = LAX_CROSS_LAX_SECURE
  };
  // Makes a status that says include and should not warn.
  CookieInclusionStatus();

  // Make a status that contains the given exclusion reason.
  explicit CookieInclusionStatus(ExclusionReason reason);
  // Makes a status that contains the given exclusion reason and warning.
  CookieInclusionStatus(ExclusionReason reason, WarningReason warning);

  bool operator==(const CookieInclusionStatus& other) const;
  bool operator!=(const CookieInclusionStatus& other) const;

  // Whether the status is to include the cookie, and has no other reasons for
  // exclusion.
  bool IsInclude() const;

  // Whether the given reason for exclusion is present.
  bool HasExclusionReason(ExclusionReason status_type) const;

  // Whether the given reason for exclusion is present, and is the ONLY reason
  // for exclusion.
  bool HasOnlyExclusionReason(ExclusionReason status_type) const;

  // Add an exclusion reason.
  void AddExclusionReason(ExclusionReason status_type);

  // Remove an exclusion reason.
  void RemoveExclusionReason(ExclusionReason reason);

  // If the cookie would have been excluded for reasons other than
  // SAMESITE_UNSPECIFIED_TREATED_AS_LAX or SAMESITE_NONE_INSECURE, don't bother
  // warning about it (clear the warning).
  void MaybeClearSameSiteWarning();

  // Whether to record the breaking downgrade metrics if the cookie is included
  // or if it's only excluded because of insufficient same-site context.
  bool ShouldRecordDowngradeMetrics() const;

  // Whether the cookie should be warned about.
  bool ShouldWarn() const;

  // Whether the given reason for warning is present.
  bool HasWarningReason(WarningReason reason) const;

  // Whether a schemeful downgrade warning is present.
  // A schemeful downgrade means that an included cookie with an effective
  // SameSite is experiencing a SameSiteCookieContext::|context| ->
  // SameSiteCookieContext::|schemeful_context| downgrade that will prevent its
  // access schemefully. If the function returns true and |reason| is valid then
  // |reason| will contain which warning was found.
  bool HasDowngradeWarning(
      CookieInclusionStatus::WarningReason* reason = nullptr) const;

  // Add an warning reason.
  void AddWarningReason(WarningReason reason);

  // Remove an warning reason.
  void RemoveWarningReason(WarningReason reason);

  // Used for serialization/deserialization.
  uint32_t exclusion_reasons() const { return exclusion_reasons_; }
  void set_exclusion_reasons(uint32_t exclusion_reasons) {
    exclusion_reasons_ = exclusion_reasons;
  }

  uint32_t warning_reasons() const { return warning_reasons_; }
  void set_warning_reasons(uint32_t warning_reasons) {
    warning_reasons_ = warning_reasons;
  }

  ContextDowngradeMetricValues GetBreakingDowngradeMetricsEnumValue(
      const GURL& url) const;

  // Get exclusion reason(s) and warning in string format.
  std::string GetDebugString() const;

  // Checks that the underlying bit vector representation doesn't contain any
  // extraneous bits that are not mapped to any enum values. Does not check
  // for reasons which semantically cannot coexist.
  bool IsValid() const;

  // Checks whether the exclusion reasons are exactly the set of exclusion
  // reasons in the vector. (Ignores warnings.)
  bool HasExactlyExclusionReasonsForTesting(
      std::vector<ExclusionReason> reasons) const;

  // Checks whether the warning reasons are exactly the set of warning
  // reasons in the vector. (Ignores exclusions.)
  bool HasExactlyWarningReasonsForTesting(
      std::vector<WarningReason> reasons) const;

  // Makes a status that contains the given exclusion reasons and warning.
  static CookieInclusionStatus MakeFromReasonsForTesting(
      std::vector<ExclusionReason> reasons,
      std::vector<WarningReason> warnings = std::vector<WarningReason>());

 private:
  // A bit vector of the applicable exclusion reasons.
  uint32_t exclusion_reasons_ = 0u;

  // A bit vector of the applicable warning reasons.
  uint32_t warning_reasons_ = 0u;
};

NET_EXPORT inline std::ostream& operator<<(std::ostream& os,
                                           const CookieInclusionStatus status) {
  return os << status.GetDebugString();
}

}  // namespace net

#endif  // NET_COOKIES_COOKIE_INCLUSION_STATUS_H_