cookie_inclusion_status.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef NET_COOKIES_COOKIE_INCLUSION_STATUS_H_
  5. #define NET_COOKIES_COOKIE_INCLUSION_STATUS_H_
  6. #include <bitset>
  7. #include <ostream>
  8. #include <string>
  9. #include <vector>
  10. #include "net/base/net_export.h"
  11. class GURL;
  12. namespace net {
  13. // This class represents if a cookie was included or excluded in a cookie get or
  14. // set operation, and if excluded why. It holds a vector of reasons for
  15. // exclusion, where cookie inclusion is represented by the absence of any
  16. // exclusion reasons. Also marks whether a cookie should be warned about, e.g.
  17. // for deprecation or intervention reasons.
  18. // TODO(crbug.com/1310444): Improve serialization validation comments.
  19. class NET_EXPORT CookieInclusionStatus {
  20. public:
  21. // Types of reasons why a cookie might be excluded.
  22. // If adding a ExclusionReason, please also update the GetDebugString()
  23. // method.
  24. enum ExclusionReason {
  25. EXCLUDE_UNKNOWN_ERROR = 0,
  26. // Statuses applied when accessing a cookie (either sending or setting):
  27. // Cookie was HttpOnly, but the attempted access was through a non-HTTP API.
  28. EXCLUDE_HTTP_ONLY = 1,
  29. // Cookie was Secure, but the URL was not allowed to access Secure cookies.
  30. EXCLUDE_SECURE_ONLY = 2,
  31. // The cookie's domain attribute did not match the domain of the URL
  32. // attempting access.
  33. EXCLUDE_DOMAIN_MISMATCH = 3,
  34. // The cookie's path attribute did not match the path of the URL attempting
  35. // access.
  36. EXCLUDE_NOT_ON_PATH = 4,
  37. // The cookie had SameSite=Strict, and the attempted access did not have an
  38. // appropriate SameSiteCookieContext.
  39. EXCLUDE_SAMESITE_STRICT = 5,
  40. // The cookie had SameSite=Lax, and the attempted access did not have an
  41. // appropriate SameSiteCookieContext.
  42. EXCLUDE_SAMESITE_LAX = 6,
  43. // The cookie did not specify a SameSite attribute, and therefore was
  44. // treated as if it were SameSite=Lax, and the attempted access did not have
  45. // an appropriate SameSiteCookieContext.
  46. EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX = 7,
  47. // The cookie specified SameSite=None, but it was not Secure.
  48. EXCLUDE_SAMESITE_NONE_INSECURE = 8,
  49. // Caller did not allow access to the cookie.
  50. EXCLUDE_USER_PREFERENCES = 9,
  51. // The cookie specified SameParty, but was used in a cross-party context.
  52. EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT = 10,
  53. // Statuses only applied when creating/setting cookies:
  54. // Cookie was malformed and could not be stored, due to problem(s) while
  55. // parsing.
  56. // TODO(crbug.com/1228815): Use more specific reasons for parsing errors.
  57. EXCLUDE_FAILURE_TO_STORE = 11,
  58. // Attempted to set a cookie from a scheme that does not support cookies.
  59. EXCLUDE_NONCOOKIEABLE_SCHEME = 12,
  60. // Cookie would have overwritten a Secure cookie, and was not allowed to do
  61. // so. (See "Leave Secure Cookies Alone":
  62. // https://tools.ietf.org/html/draft-west-leave-secure-cookies-alone-05 )
  63. EXCLUDE_OVERWRITE_SECURE = 13,
  64. // Cookie would have overwritten an HttpOnly cookie, and was not allowed to
  65. // do so.
  66. EXCLUDE_OVERWRITE_HTTP_ONLY = 14,
  67. // Cookie was set with an invalid Domain attribute.
  68. EXCLUDE_INVALID_DOMAIN = 15,
  69. // Cookie was set with an invalid __Host- or __Secure- prefix.
  70. EXCLUDE_INVALID_PREFIX = 16,
  71. // Cookie was set with an invalid SameParty attribute in combination with
  72. // other attributes. (SameParty is invalid if Secure is not present, or if
  73. // SameSite=Strict is present.)
  74. EXCLUDE_INVALID_SAMEPARTY = 17,
  75. /// Cookie was set with an invalid Partitioned attribute, which is only
  76. // valid if the cookie has a __Host- prefix and does not have the SameParty
  77. // attribute.
  78. EXCLUDE_INVALID_PARTITIONED = 18,
  79. // Cookie exceeded the name/value pair size limit.
  80. EXCLUDE_NAME_VALUE_PAIR_EXCEEDS_MAX_SIZE = 19,
  81. // Cookie exceeded the attribute size limit. Note that this exclusion value
  82. // won't be used by code that parses cookie lines since RFC6265bis
  83. // indicates that large attributes should be ignored instead of causing the
  84. // whole cookie to be rejected. There will be a corresponding WarningReason
  85. // to notify users that an attribute value was ignored in that case.
  86. EXCLUDE_ATTRIBUTE_VALUE_EXCEEDS_MAX_SIZE = 20,
  87. // Cookie was set with a Domain attribute containing non ASCII characters.
  88. EXCLUDE_DOMAIN_NON_ASCII = 21,
  89. // This should be kept last.
  90. NUM_EXCLUSION_REASONS
  91. };
  92. // Reason to warn about a cookie. Any information contained in WarningReason
  93. // of an included cookie may be passed to an untrusted renderer.
  94. // If you add one, please update GetDebugString().
  95. enum WarningReason {
  96. // Of the following 3 SameSite warnings, there will be, at most, a single
  97. // active one.
  98. // Warn if a cookie with unspecified SameSite attribute is used in a
  99. // cross-site context.
  100. WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT = 0,
  101. // Warn if a cookie with SameSite=None is not Secure.
  102. WARN_SAMESITE_NONE_INSECURE = 1,
  103. // Warn if a cookie with unspecified SameSite attribute is defaulted into
  104. // Lax and is sent on a request with unsafe method, only because it is new
  105. // enough to activate the Lax-allow-unsafe intervention.
  106. WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE = 2,
  107. // The following warnings indicate that an included cookie with an effective
  108. // SameSite is experiencing a SameSiteCookieContext::|context| ->
  109. // SameSiteCookieContext::|schemeful_context| downgrade that will prevent
  110. // its access schemefully.
  111. // This situation means that a cookie is accessible when the
  112. // SchemefulSameSite feature is disabled but not when it's enabled,
  113. // indicating changed behavior and potential breakage.
  114. //
  115. // For example, a Strict to Lax downgrade for an effective SameSite=Strict
  116. // cookie:
  117. // This cookie would be accessible in the Strict context as its SameSite
  118. // value is Strict. However its context for schemeful same-site becomes Lax.
  119. // A strict cookie cannot be accessed in a Lax context and therefore the
  120. // behavior has changed.
  121. // As a counterexample, a Strict to Lax downgrade for an effective
  122. // SameSite=Lax cookie: A Lax cookie can be accessed in both Strict and Lax
  123. // contexts so there is no behavior change (and we don't warn about it).
  124. //
  125. // The warnings are in the following format:
  126. // WARN_{context}_{schemeful_context}_DOWNGRADE_{samesite_value}_SAMESITE
  127. //
  128. // Of the following 5 SameSite warnings, there will be, at most, a single
  129. // active one.
  130. // Strict to Lax downgrade for an effective SameSite=Strict cookie.
  131. // This warning is only applicable for cookies being sent because a Strict
  132. // cookie will be set in both Strict and Lax Contexts so the downgrade will
  133. // not affect it.
  134. WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE = 3,
  135. // Strict to Cross-site downgrade for an effective SameSite=Strict cookie.
  136. // This also applies to Strict to Lax Unsafe downgrades due to Lax Unsafe
  137. // behaving like Cross-site.
  138. WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE = 4,
  139. // Strict to Cross-site downgrade for an effective SameSite=Lax cookie.
  140. // This also applies to Strict to Lax Unsafe downgrades due to Lax Unsafe
  141. // behaving like Cross-site.
  142. WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE = 5,
  143. // Lax to Cross-site downgrade for an effective SameSite=Strict cookie.
  144. // This warning is only applicable for cookies being set because a Strict
  145. // cookie will not be sent in a Lax context so the downgrade would not
  146. // affect it.
  147. WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE = 6,
  148. // Lax to Cross-site downgrade for an effective SameSite=Lax cookie.
  149. WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE = 7,
  150. // Advisory warning attached when a Secure cookie is accessed from (sent to,
  151. // or set by) a non-cryptographic URL. This can happen if the URL is
  152. // potentially trustworthy (e.g. a localhost URL, or another URL that
  153. // the CookieAccessDelegate is configured to allow).
  154. // TODO(chlily): Add metrics for how often and where this occurs.
  155. WARN_SECURE_ACCESS_GRANTED_NON_CRYPTOGRAPHIC = 8,
  156. // The cookie was treated as SameParty. This is different from looking at
  157. // whether the cookie has the SameParty attribute, since we may choose to
  158. // ignore that attribute for one reason or another. E.g., we ignore the
  159. // SameParty attribute if the site is not a member of a nontrivial
  160. // First-Party Set.
  161. WARN_TREATED_AS_SAMEPARTY = 9,
  162. // The cookie was excluded solely for SameParty reasons (i.e. it was in
  163. // cross-party context), but would have been included by SameSite. (This can
  164. // only occur in cross-party, cross-site contexts, for cookies that are
  165. // 'SameParty; SameSite=None'.)
  166. WARN_SAMEPARTY_EXCLUSION_OVERRULED_SAMESITE = 10,
  167. // The cookie was included due to SameParty, even though it would have been
  168. // excluded by SameSite. (This can only occur in same-party, cross-site
  169. // contexts, for cookies that are 'SameParty; SameSite=Lax'.)
  170. WARN_SAMEPARTY_INCLUSION_OVERRULED_SAMESITE = 11,
  171. // The cookie would have been included prior to the spec change considering
  172. // redirects in the SameSite context calculation
  173. // (https://github.com/httpwg/http-extensions/pull/1348)
  174. // but would have been excluded after the spec change, due to a cross-site
  175. // redirect causing the SameSite context calculation to be downgraded.
  176. // This is applied if and only if the cookie's inclusion was changed by
  177. // considering redirect chains (and is applied regardless of which context
  178. // was actually used for the inclusion decision). This is not applied if
  179. // the context was downgraded but the cookie would have been
  180. // included/excluded in both cases.
  181. WARN_CROSS_SITE_REDIRECT_DOWNGRADE_CHANGES_INCLUSION = 12,
  182. // The cookie exceeded the attribute size limit. RFC6265bis indicates that
  183. // large attributes should be ignored instead of causing the whole cookie
  184. // to be rejected. This is applied by the code that parses cookie lines and
  185. // notifies the user that an attribute value was ignored.
  186. WARN_ATTRIBUTE_VALUE_EXCEEDS_MAX_SIZE = 13,
  187. // Cookie was set with a Domain attribute containing non ASCII characters.
  188. WARN_DOMAIN_NON_ASCII = 14,
  189. // This should be kept last.
  190. NUM_WARNING_REASONS
  191. };
  192. // These enums encode the context downgrade warnings + the secureness of the
  193. // url sending/setting the cookie. They're used for metrics only. The format
  194. // is k{context}{schemeful_context}{samesite_value}{securness}.
  195. // kNoDowngrade{securness} indicates that a cookie didn't have a breaking
  196. // context downgrade and was A) included B) excluded only due to insufficient
  197. // same-site context. I.e. the cookie wasn't excluded due to other reasons
  198. // such as third-party cookie blocking. Keep this in line with
  199. // SameSiteCookieContextBreakingDowngradeWithSecureness in enums.xml.
  200. enum class ContextDowngradeMetricValues {
  201. kNoDowngradeInsecure = 0,
  202. kNoDowngradeSecure = 1,
  203. kStrictLaxStrictInsecure = 2,
  204. kStrictCrossStrictInsecure = 3,
  205. kStrictCrossLaxInsecure = 4,
  206. kLaxCrossStrictInsecure = 5,
  207. kLaxCrossLaxInsecure = 6,
  208. kStrictLaxStrictSecure = 7,
  209. kStrictCrossStrictSecure = 8,
  210. kStrictCrossLaxSecure = 9,
  211. kLaxCrossStrictSecure = 10,
  212. kLaxCrossLaxSecure = 11,
  213. // Keep last.
  214. kMaxValue = kLaxCrossLaxSecure
  215. };
  216. using ExclusionReasonBitset =
  217. std::bitset<ExclusionReason::NUM_EXCLUSION_REASONS>;
  218. using WarningReasonBitset = std::bitset<WarningReason::NUM_WARNING_REASONS>;
  219. // Makes a status that says include and should not warn.
  220. CookieInclusionStatus();
  221. // Make a status that contains the given exclusion reason.
  222. explicit CookieInclusionStatus(ExclusionReason reason);
  223. // Makes a status that contains the given exclusion reason and warning.
  224. CookieInclusionStatus(ExclusionReason reason, WarningReason warning);
  225. // Makes a status that contains the given warning.
  226. explicit CookieInclusionStatus(WarningReason warning);
  227. // Copyable.
  228. CookieInclusionStatus(const CookieInclusionStatus& other);
  229. CookieInclusionStatus& operator=(const CookieInclusionStatus& other);
  230. bool operator==(const CookieInclusionStatus& other) const;
  231. bool operator!=(const CookieInclusionStatus& other) const;
  232. // Whether the status is to include the cookie, and has no other reasons for
  233. // exclusion.
  234. bool IsInclude() const;
  235. // Whether the given reason for exclusion is present.
  236. bool HasExclusionReason(ExclusionReason status_type) const;
  237. // Whether the given reason for exclusion is present, and is the ONLY reason
  238. // for exclusion.
  239. bool HasOnlyExclusionReason(ExclusionReason status_type) const;
  240. // Add an exclusion reason.
  241. void AddExclusionReason(ExclusionReason status_type);
  242. // Remove an exclusion reason.
  243. void RemoveExclusionReason(ExclusionReason reason);
  244. // Remove multiple exclusion reasons.
  245. void RemoveExclusionReasons(const std::vector<ExclusionReason>& reasons);
  246. // If the cookie would have been excluded for reasons other than
  247. // SameSite-related reasons, don't bother warning about it (clear the
  248. // warning).
  249. void MaybeClearSameSiteWarning();
  250. // Whether to record the breaking downgrade metrics if the cookie is included
  251. // or if it's only excluded because of insufficient same-site context.
  252. bool ShouldRecordDowngradeMetrics() const;
  253. // Whether the cookie should be warned about.
  254. bool ShouldWarn() const;
  255. // Whether the given reason for warning is present.
  256. bool HasWarningReason(WarningReason reason) const;
  257. // Whether a schemeful downgrade warning is present.
  258. // A schemeful downgrade means that an included cookie with an effective
  259. // SameSite is experiencing a SameSiteCookieContext::|context| ->
  260. // SameSiteCookieContext::|schemeful_context| downgrade that will prevent its
  261. // access schemefully. If the function returns true and |reason| is valid then
  262. // |reason| will contain which warning was found.
  263. bool HasDowngradeWarning(
  264. CookieInclusionStatus::WarningReason* reason = nullptr) const;
  265. // Add an warning reason.
  266. void AddWarningReason(WarningReason reason);
  267. // Remove an warning reason.
  268. void RemoveWarningReason(WarningReason reason);
  269. // Used for serialization/deserialization.
  270. ExclusionReasonBitset exclusion_reasons() const { return exclusion_reasons_; }
  271. void set_exclusion_reasons(ExclusionReasonBitset exclusion_reasons) {
  272. exclusion_reasons_ = exclusion_reasons;
  273. }
  274. WarningReasonBitset warning_reasons() const { return warning_reasons_; }
  275. void set_warning_reasons(WarningReasonBitset warning_reasons) {
  276. warning_reasons_ = warning_reasons;
  277. }
  278. ContextDowngradeMetricValues GetBreakingDowngradeMetricsEnumValue(
  279. const GURL& url) const;
  280. // Get exclusion reason(s) and warning in string format.
  281. std::string GetDebugString() const;
  282. // Checks whether the exclusion reasons are exactly the set of exclusion
  283. // reasons in the vector. (Ignores warnings.)
  284. bool HasExactlyExclusionReasonsForTesting(
  285. std::vector<ExclusionReason> reasons) const;
  286. // Checks whether the warning reasons are exactly the set of warning
  287. // reasons in the vector. (Ignores exclusions.)
  288. bool HasExactlyWarningReasonsForTesting(
  289. std::vector<WarningReason> reasons) const;
  290. // Validates mojo data, since mojo does not support bitsets.
  291. // TODO(crbug.com/1310444): Improve serialization validation comments
  292. // and check for mutually exclusive values.
  293. static bool ValidateExclusionAndWarningFromWire(uint32_t exclusion_reasons,
  294. uint32_t warning_reasons);
  295. // Makes a status that contains the given exclusion reasons and warning.
  296. static CookieInclusionStatus MakeFromReasonsForTesting(
  297. std::vector<ExclusionReason> reasons,
  298. std::vector<WarningReason> warnings = std::vector<WarningReason>());
  299. private:
  300. // Returns the `exclusion_reasons_` with the given `reasons` unset.
  301. ExclusionReasonBitset ExclusionReasonsWithout(
  302. const std::vector<ExclusionReason>& reasons) const;
  303. // A bit vector of the applicable exclusion reasons.
  304. ExclusionReasonBitset exclusion_reasons_;
  305. // A bit vector of the applicable warning reasons.
  306. WarningReasonBitset warning_reasons_;
  307. };
  308. NET_EXPORT inline std::ostream& operator<<(std::ostream& os,
  309. const CookieInclusionStatus status) {
  310. return os << status.GetDebugString();
  311. }
  312. // Provided to allow gtest to create more helpful error messages, instead of
  313. // printing hex.
  314. inline void PrintTo(const CookieInclusionStatus& cis, std::ostream* os) {
  315. *os << cis;
  316. }
  317. } // namespace net
  318. #endif // NET_COOKIES_COOKIE_INCLUSION_STATUS_H_