• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 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_DEVICE_BOUND_SESSIONS_COOKIE_CRAVING_H_
6 #define NET_DEVICE_BOUND_SESSIONS_COOKIE_CRAVING_H_
7 
8 #include <optional>
9 #include <string>
10 
11 #include "base/time/time.h"
12 #include "net/base/net_export.h"
13 #include "net/cookies/cookie_base.h"
14 #include "net/cookies/cookie_constants.h"
15 #include "net/cookies/cookie_partition_key.h"
16 
17 namespace net {
18 class CanonicalCookie;
19 }
20 
21 namespace net::device_bound_sessions {
22 
23 namespace proto {
24 class CookieCraving;
25 }
26 
27 // This class represents the need for a certain cookie to be present. It is not
28 // a cookie itself, but rather represents a requirement which can be satisfied
29 // by a real cookie (i.e. a CanonicalCookie). Each CookieCraving is specified by
30 // and associated with a DBSC (Device Bound Session Credentials) session.
31 //
32 // In general, CookieCraving behavior is intended to be as close as possible to
33 // CanonicalCookie, especially the inclusion logic, since they need to be
34 // matched up. However, some notable differences include:
35 //
36 // CookieCraving does not have a value field, i.e. they only have a name (and
37 // other attributes). The name can be the empty string. The name of a cookie is
38 // needed to identify it, but the value of a cookie is not relevant to its
39 // inclusion or exclusion, so CookieCraving omits it.
40 //
41 // CookieCraving does not have an expiry date. The expiry date of a
42 // CanonicalCookie often depends upon the creation time (if it is set via
43 // Max-Age), and a DBSC session config is not necessarily created at the same
44 // time as its corresponding Set-Cookie header, so we cannot guarantee that
45 // they'd match. DBSC also does not require a specific expiry date for the
46 // cookies whose presence it guarantees.
47 //
48 // CookieCraving does not implement lax-allow-unsafe behavior (it does not
49 // set a non-zero age threshold for it). The default CanonicalCookie
50 // lax-allow-unsafe behavior is problematic because it can result in two
51 // identical set-cookie lines (set from the same URL) exhibiting different
52 // inclusion results, if they happen to be on opposite sides of the
53 // lax-allow-unsafe age threshold. By not implementing lax-allow-unsafe,
54 // CookieCraving may sometimes be excluded even when a corresponding
55 // CanonicalCookie would be included for being under its lax-allow-unsafe age
56 // threshold. This means that servers deploying DBSC with SameSite-unspecified
57 // cookies SHOULD NOT rely on the presence of SameSite-unspecified cookies
58 // within 2 minutes of their creation time on cross-site POST and other unsafe
59 // request types, as DBSC cannot make any such guarantee.
60 class NET_EXPORT CookieCraving : public CookieBase {
61  public:
62   // Creates a new CookieCraving in the context of `url`, given a `name` and
63   // associated cookie `attributes`. (Note that CookieCravings do not have a
64   // "value".) `url` must be valid. `creation_time` may not be null. May return
65   // nullopt if an attribute value is invalid. If a CookieCraving is returned,
66   // it will satisfy IsValid(). If there is leading or trailing whitespace in
67   // `name`, it will get trimmed.
68   //
69   // `cookie_partition_key` only needs to be present if the attributes contain
70   // the Partitioned attribute. std::nullopt indicates an unpartitioned
71   // CookieCraving will be created. If there is a partition key but the
72   // attributes do not specify Partitioned, the resulting CookieCraving will be
73   // unpartitioned. If the partition_key is nullopt, the CookieCraving will
74   // always be unpartitioned even if the attributes specify Partitioned.
75   //
76   // SameSite and HttpOnly related parameters are not checked here,
77   // so creation of CookieCravings with e.g. SameSite=Strict from a cross-site
78   // context is allowed. Create() also does not check whether `url` has a secure
79   // scheme if attempting to create a Secure cookie. The Secure, SameSite, and
80   // HttpOnly related parameters should be checked when deciding CookieCraving
81   // inclusion for a given request/context.
82   //
83   // In general this is intended to closely mirror CanonicalCookie::Create.
84   // However, there are some simplifying assumptions made*, and metrics are not
85   // (currently) logged so as to not interfere with CanonicalCookie metrics.
86   // There is also no (current) need for a CookieInclusionStatus to be returned.
87   //
88   // * Simplifying assumptions (differing from CanonicalCookie):
89   //  - The Domain() member of a CookieCraving is required to be non-empty,
90   //    which CanonicalCookie does not require.
91   //  - Cookie name prefixes (__Host- and __Secure-) are always checked
92   //    case-insensitively, unlike CanonicalCookie which reads a Feature value
93   //    to decide whether to check insensitively.
94   //  - CanonicalCookie allows non-cryptographic URLs to create a cookie with a
95   //    secure source_scheme, if that cookie was Secure, on the basis that that
96   //    URL might be trustworthy when checked later. CookieCraving does not
97   //    allow this.
98   static std::optional<CookieCraving> Create(
99       const GURL& url,
100       const std::string& name,
101       const std::string& attributes,
102       base::Time creation_time,
103       std::optional<CookiePartitionKey> cookie_partition_key);
104 
105   CookieCraving(const CookieCraving& other);
106   CookieCraving(CookieCraving&& other);
107   CookieCraving& operator=(const CookieCraving& other);
108   CookieCraving& operator=(CookieCraving&& other);
109   ~CookieCraving() override;
110 
111   // Returns whether all CookieCraving fields are consistent, in canonical form,
112   // etc. (Mostly analogous to CanonicalCookie::IsCanonical, except without
113   // checks for access time.) Essentially, if this returns true, then this
114   // CookieCraving instance could have been created by Create().
115   // Other public methods of this class may not be called if IsValid() is false.
116   bool IsValid() const;
117 
118   // Returns whether the given "real" cookie satisfies this CookieCraving, in
119   // the sense that DBSC will consider the required cookie present.
120   // The provided CanonicalCookie must be canonical.
121   bool IsSatisfiedBy(const CanonicalCookie& canonical_cookie) const;
122 
123   std::string DebugString() const;
124 
125   bool IsEqualForTesting(const CookieCraving& other) const;
126 
127   // May return an invalid instance.
128   static CookieCraving CreateUnsafeForTesting(
129       std::string name,
130       std::string domain,
131       std::string path,
132       base::Time creation,
133       bool secure,
134       bool httponly,
135       CookieSameSite same_site,
136       std::optional<CookiePartitionKey> partition_key,
137       CookieSourceScheme source_scheme,
138       int source_port);
139 
140   // Returns a protobuf object. May only be called for
141   // a valid CookieCraving object.
142   proto::CookieCraving ToProto() const;
143 
144   // Creates a CookieCraving object from a protobuf
145   // object. If the protobuf contents are invalid,
146   // a std::nullopt is returned.
147   static std::optional<CookieCraving> CreateFromProto(
148       const proto::CookieCraving& proto);
149 
150  private:
151   CookieCraving();
152 
153   // Prefer Create() over this constructor. This may return non-valid instances.
154   CookieCraving(std::string name,
155                 std::string domain,
156                 std::string path,
157                 base::Time creation,
158                 bool secure,
159                 bool httponly,
160                 CookieSameSite same_site,
161                 std::optional<CookiePartitionKey> partition_key,
162                 CookieSourceScheme source_scheme,
163                 int source_port);
164 };
165 
166 // Outputs a debug string, e.g. for more helpful test failure messages.
167 NET_EXPORT std::ostream& operator<<(std::ostream& os, const CookieCraving& cc);
168 
169 }  // namespace net::device_bound_sessions
170 
171 #endif  // NET_DEVICE_BOUND_SESSIONS_COOKIE_CRAVING_H_
172