1 // Copyright 2012 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_COOKIES_COOKIE_UTIL_H_ 6 #define NET_COOKIES_COOKIE_UTIL_H_ 7 8 #include <optional> 9 #include <string> 10 #include <vector> 11 12 #include "base/functional/callback_forward.h" 13 #include "base/time/time.h" 14 #include "base/types/optional_ref.h" 15 #include "net/base/net_export.h" 16 #include "net/cookies/canonical_cookie.h" 17 #include "net/cookies/cookie_access_result.h" 18 #include "net/cookies/cookie_constants.h" 19 #include "net/cookies/cookie_options.h" 20 #include "net/cookies/cookie_setting_override.h" 21 #include "net/cookies/site_for_cookies.h" 22 #include "net/first_party_sets/first_party_set_metadata.h" 23 #include "net/first_party_sets/first_party_sets_cache_filter.h" 24 #include "net/storage_access_api/status.h" 25 #include "url/origin.h" 26 27 class GURL; 28 29 namespace net { 30 31 class IsolationInfo; 32 class SchemefulSite; 33 class CookieAccessDelegate; 34 class CookieInclusionStatus; 35 class ParsedCookie; 36 37 namespace cookie_util { 38 39 // Constants for use in VLOG 40 const int kVlogPerCookieMonster = 1; 41 const int kVlogSetCookies = 7; 42 const int kVlogGarbageCollection = 5; 43 44 // This enum must match the numbering for StorageAccessResult in 45 // histograms/metadata/storage/enums.xml. Do not reorder or remove items, only 46 // add new items at the end. 47 enum class StorageAccessResult { 48 ACCESS_BLOCKED = 0, 49 ACCESS_ALLOWED = 1, 50 ACCESS_ALLOWED_STORAGE_ACCESS_GRANT = 2, 51 OBSOLETE_ACCESS_ALLOWED_FORCED = 3 /*(DEPRECATED)*/, 52 ACCESS_ALLOWED_TOP_LEVEL_STORAGE_ACCESS_GRANT = 4, 53 ACCESS_ALLOWED_3PCD_TRIAL = 5, 54 ACCESS_ALLOWED_3PCD_METADATA_GRANT = 6, 55 ACCESS_ALLOWED_3PCD_HEURISTICS_GRANT = 7, 56 // ACCESS_ALLOWED_CORS_EXCEPTION = 8, // Deprecated 57 ACCESS_ALLOWED_TOP_LEVEL_3PCD_TRIAL = 9, 58 ACCESS_ALLOWED_SCHEME = 10, 59 kMaxValue = ACCESS_ALLOWED_SCHEME, 60 }; 61 62 // This enum's values correspond to the values of the HTTP request header 63 // `Sec-Fetch-Storage-Access`, which is applied to cross-site requests. 64 enum class StorageAccessStatus { 65 // Applies to context that does not have unpartitioned cookie access, and does 66 // not have the `storage-access` permission. 67 kNone = 0, 68 // Applies to context that has `storage-access` permission, but has not opted 69 // into using it; the context also does not have unpartitioned cookie access 70 // through some other means. 71 kInactive = 1, 72 // Applies to context that has unpartitioned cookie access. 73 kActive = 2 74 }; 75 76 // These values are persisted to logs. Entries should not be renumbered and 77 // numeric values should never be reused. 78 // The values of this enum correspond to possible reasons a request's 79 // StorageAccessStatus may be absent (nullopt), as well as the possible values 80 // when it is non-nullopt. 81 // 82 // LINT.IfChange(StorageAccessStatusOutcome) 83 enum class StorageAccessStatusOutcome { 84 // The feature is disabled. 85 kOmittedFeatureDisabled = 0, 86 // The request is same-site. 87 kOmittedSameSite = 1, 88 // The storage access status is `none`. 89 kValueNone = 2, 90 // The storage access status is `inactive`. 91 kValueInactive = 3, 92 // The storage access status is `active`. 93 kValueActive = 4, 94 kMaxValue = kValueActive 95 }; 96 // LINT.ThenChange(//tools/metrics/histograms/metadata/storage/enums.xml:StorageAccessStatusOutcome) 97 98 // These values are persisted to logs. Entries should not be renumbered and 99 // numeric values should never be reused. 100 // The values of this enum correspond to possible reasons the 101 // `Sec-Fetch-Storage-Access` header may be omitted from a request, as well as 102 // the possible values of the header when it is included. 103 enum class SecFetchStorageAccessOutcome { 104 // The request's storage access status is nullopt. 105 kOmittedStatusMissing = 0, 106 // The request's credentials mode is not "include". 107 kOmittedRequestOmitsCredentials = 1, 108 // The `Sec-Fetch-Storage-Access` header is included and has the value `none`. 109 kValueNone = 2, 110 // The `Sec-Fetch-Storage-Access` header is included and has the value 111 // `inactive`. 112 kValueInactive = 3, 113 // The `Sec-Fetch-Storage-Access` header is included and has the value 114 // `active`. 115 kValueActive = 4, 116 kMaxValue = kValueActive 117 }; 118 119 // These values are persisted to logs. Entries should not be renumbered and 120 // numeric values should never be reused. 121 // The values of this enum correspond to the possible outcomes of a call to 122 // URLRequest::ShouldSetLoadWithStorageAccess(). 123 // 124 // LINT.IfChange(ActivateStorageAccessLoadOutcome) 125 enum class ActivateStorageAccessLoadOutcome { 126 // Applies when the `Activate-Storage-Access` header behavior is not enabled 127 // under the existing feature flags or content settings. 128 kFailureHeaderDisabled = 0, 129 // Applies when a response includes the `Activate-Storage-Access: load` 130 // header, but its corresponding request either has an omitted storage access 131 // status, or has a storage access status of `none`. 132 kFailureInvalidStatus = 1, 133 // Applies when a response includes the `Activate-Storage-Access: load` 134 // header, and that header is honored by the browser. 135 kSuccess = 2, 136 kMaxValue = kSuccess 137 }; 138 // LINT.ThenChange(//tools/metrics/histograms/metadata/storage/enums.xml:ActivateStorageAccessLoadOutcome) 139 140 // These values are persisted to logs. Entries should not be renumbered and 141 // numeric values should never be reused. 142 // The values of this enum correspond to the possible outcomes of a call to 143 // URLRequestHttpJob::NeedsRetryWithStorageAccess(). 144 // 145 // LINT.IfChange(ActivateStorageAccessRetryOutcome) 146 enum class ActivateStorageAccessRetryOutcome { 147 // Applies when the `Activate-Storage-Access` header behavior is not enabled 148 // under the existing feature flags or content settings. 149 kFailureHeaderDisabled = 0, 150 // Applies when a response includes a well-formed 151 // `Activate-Storage-Access: retry; ..." header, but the corresponding 152 // request's `Sec-Fetch-Storage-Access` header is not `inactive`. 153 kFailureIneffectiveRetry = 1, 154 // Applies when a response includes a well-formed 155 // "Activate-Storage-Access: retry; ..." header, and that header is honored 156 // by the browser. 157 kSuccess = 2, 158 kMaxValue = kSuccess 159 }; 160 // LINT.ThenChange(//tools/metrics/histograms/metadata/storage/enums.xml:ActivateStorageAccessRetryOutcome) 161 162 // Helper to fire telemetry indicating if a given request for storage was 163 // allowed or not by the provided |result|. 164 NET_EXPORT void FireStorageAccessHistogram(StorageAccessResult result); 165 166 // Returns the effective TLD+1 for a given host. This only makes sense for http 167 // and https schemes. For other schemes, the host will be returned unchanged 168 // (minus any leading period). 169 NET_EXPORT std::string GetEffectiveDomain(const std::string& scheme, 170 const std::string& host); 171 172 // Determine the actual cookie domain based on the domain string passed 173 // (if any) and the URL from which the cookie came. 174 // On success returns true, and sets cookie_domain to either a 175 // -host cookie domain (ex: "google.com") 176 // -domain cookie domain (ex: ".google.com") 177 // On success, DomainIsHostOnly(url.host()) is DCHECKed. The URL's host must not 178 // begin with a '.' character. 179 NET_EXPORT bool GetCookieDomainWithString(const GURL& url, 180 const std::string& domain_string, 181 CookieInclusionStatus& status, 182 std::string* result); 183 184 // Returns true if a domain string represents a host-only cookie, 185 // i.e. it doesn't begin with a leading '.' character. 186 NET_EXPORT bool DomainIsHostOnly(const std::string& domain_string); 187 188 // If |cookie_domain| is nonempty and starts with a "." character, this returns 189 // the substring of |cookie_domain| without the leading dot. (Note only one 190 // leading dot is stripped, if there are multiple.) Otherwise it returns 191 // |cookie_domain|. This is useful for converting from CanonicalCookie's 192 // representation of a cookie domain to the RFC's notion of a cookie's domain. 193 NET_EXPORT std::string CookieDomainAsHost(const std::string& cookie_domain); 194 195 // Parses the string with the cookie expiration time (very forgivingly). 196 // Returns the "null" time on failure. 197 // 198 // If the expiration date is below or above the platform-specific range 199 // supported by Time::FromUTCExplodeded(), then this will return Time(1) or 200 // Time::Max(), respectively. 201 NET_EXPORT base::Time ParseCookieExpirationTime(const std::string& time_string); 202 203 // Returns the canonical path based on the specified url and path attribute 204 // value. Note that this method does not enforce character set or size 205 // checks on `path_string`. 206 NET_EXPORT std::string CanonPathWithString(const GURL& url, 207 const std::string& path_string); 208 209 // Get a cookie's URL from it's domain, path, and source scheme. 210 // The first field can be the combined domain-and-host-only-flag (e.g. the 211 // string returned by CanonicalCookie::Domain()) as opposed to the domain 212 // attribute per RFC6265bis. The GURL is constructed after stripping off any 213 // leading dot. 214 // Note: the GURL returned by this method is not guaranteed to be valid. 215 NET_EXPORT GURL CookieDomainAndPathToURL(const std::string& domain, 216 const std::string& path, 217 const std::string& source_scheme); 218 NET_EXPORT GURL CookieDomainAndPathToURL(const std::string& domain, 219 const std::string& path, 220 bool is_https); 221 NET_EXPORT GURL CookieDomainAndPathToURL(const std::string& domain, 222 const std::string& path, 223 CookieSourceScheme source_scheme); 224 225 // Convenience for converting a cookie origin (domain and https pair) to a URL. 226 NET_EXPORT GURL CookieOriginToURL(const std::string& domain, bool is_https); 227 228 // Returns a URL that could have been the cookie's source. 229 // Not guaranteed to actually be the URL that set the cookie. Not guaranteed to 230 // be a valid GURL. Intended as a shim for SetCanonicalCookieAsync calls, where 231 // a source URL is required but only a source scheme may be available. 232 NET_EXPORT GURL SimulatedCookieSource(const CanonicalCookie& cookie, 233 const std::string& source_scheme); 234 235 // Provisional evaluation of acceptability of setting secure cookies on 236 // `source_url` based only on the `source_url`'s scheme and whether it 237 // is a localhost URL. If this returns kNonCryptographic, it may be upgraded to 238 // kTrustworthy by a CookieAccessDelegate when the cookie operation is being 239 // performed, as the delegate may have access to user settings like manually 240 // configured test domains which declare additional things trustworthy. 241 NET_EXPORT CookieAccessScheme ProvisionalAccessScheme(const GURL& source_url); 242 243 // |domain| is the output of cookie.Domain() for some cookie. This returns true 244 // if a |domain| indicates that the cookie can be accessed by |host|. 245 // See comment on CanonicalCookie::IsDomainMatch(). 246 NET_EXPORT bool IsDomainMatch(const std::string& domain, 247 const std::string& host); 248 249 // Returns true if the given |url_path| path-matches |cookie_path| 250 // as described in section 5.1.4 in RFC 6265. This returns true if |cookie_path| 251 // and |url_path| are identical, or if |url_path| is a subdirectory of 252 // |cookie_path|. 253 NET_EXPORT bool IsOnPath(const std::string& cookie_path, 254 const std::string& url_path); 255 256 // Returns the CookiePrefix (or COOKIE_PREFIX_NONE if none) that 257 // applies to the given cookie |name|. 258 CookiePrefix GetCookiePrefix(const std::string& name); 259 260 // Returns true if the cookie does not violate any constraints imposed 261 // by the cookie name's prefix, as described in 262 // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-13#name-cookie-name-prefixes 263 bool IsCookiePrefixValid(CookiePrefix prefix, 264 const GURL& url, 265 const ParsedCookie& parsed_cookie); 266 // As above. `secure`, `domain`, and `path` are the raw attribute values (i.e. 267 // as taken from a ParsedCookie), NOT in normalized form as represented in 268 // CookieBase. 269 bool IsCookiePrefixValid(CookiePrefix prefix, 270 const GURL& url, 271 bool secure, 272 const std::string& domain, 273 const std::string& path); 274 275 // Returns true iff the cookie is a partitioned cookie with a nonce or that 276 // does not violate the semantics of the Partitioned attribute: 277 // - Must have the Secure attribute OR the cookie partition contains a nonce. 278 bool IsCookiePartitionedValid(const GURL& url, 279 const ParsedCookie& parsed_cookie, 280 bool partition_has_nonce); 281 bool IsCookiePartitionedValid(const GURL& url, 282 bool secure, 283 bool is_partitioned, 284 bool partition_has_nonce); 285 286 // A ParsedRequestCookie consists of the key and value of the cookie. 287 using ParsedRequestCookie = std::pair<std::string, std::string>; 288 using ParsedRequestCookies = std::vector<ParsedRequestCookie>; 289 290 // Assumes that |header_value| is the cookie header value of a HTTP Request 291 // following the cookie-string schema of RFC 6265, section 4.2.1, and returns 292 // cookie name/value pairs. If cookie values are presented in double quotes, 293 // these will appear in |parsed_cookies| as well. The cookie header can be 294 // written by non-Chromium consumers (such as extensions), so the header may not 295 // be well-formed. 296 NET_EXPORT void ParseRequestCookieLine(const std::string& header_value, 297 ParsedRequestCookies* parsed_cookies); 298 299 // Writes all cookies of |parsed_cookies| into a HTTP Request header value 300 // that belongs to the "Cookie" header. The entries of |parsed_cookies| must 301 // already be appropriately escaped. 302 NET_EXPORT std::string SerializeRequestCookieLine( 303 const ParsedRequestCookies& parsed_cookies); 304 305 // Determines which of the cookies for the request URL can be accessed, with 306 // respect to the SameSite attribute. This applies to looking up existing 307 // cookies for HTTP requests. For looking up cookies for non-HTTP APIs (i.e., 308 // JavaScript), see ComputeSameSiteContextForScriptGet. For setting new cookies, 309 // see ComputeSameSiteContextForResponse and ComputeSameSiteContextForScriptSet. 310 // 311 // `url_chain` is a non-empty vector of URLs, the last of which is the current 312 // request URL. It represents the redirect chain of the current request. The 313 // redirect chain is used to calculate whether there has been a cross-site 314 // redirect. In order for a context to be deemed strictly same-site, there must 315 // not have been any cross-site redirects. 316 // 317 // `site_for_cookies` is the currently navigated to site that should be 318 // considered "first-party" for cookies. 319 // 320 // `initiator` is the origin ultimately responsible for getting the request 321 // issued. It may be different from `site_for_cookies`. 322 // 323 // std::nullopt for `initiator` denotes that the navigation was initiated by 324 // the user directly interacting with the browser UI, e.g. entering a URL 325 // or selecting a bookmark. 326 // 327 // `is_main_frame_navigation` is whether the request is for a navigation that 328 // targets the main frame or top-level browsing context. These requests may 329 // sometimes send SameSite=Lax cookies but not SameSite=Strict cookies. 330 // 331 // If `force_ignore_site_for_cookies` is specified, all SameSite cookies will be 332 // attached, i.e. this will return SAME_SITE_STRICT. This flag is set to true 333 // when the `site_for_cookies` is a chrome:// URL embedding a secure origin, 334 // among other scenarios. 335 // This is *not* set when the *initiator* is chrome-extension://, 336 // which is intentional, since it would be bad to let an extension arbitrarily 337 // redirect anywhere and bypass SameSite=Strict rules. 338 // 339 // See also documentation for corresponding methods on net::URLRequest. 340 // 341 // `http_method` is used to enforce the requirement that, in a context that's 342 // lax same-site but not strict same-site, SameSite=lax cookies be only sent 343 // when the method is "safe" in the RFC7231 section 4.2.1 sense. 344 NET_EXPORT CookieOptions::SameSiteCookieContext 345 ComputeSameSiteContextForRequest(const std::string& http_method, 346 const std::vector<GURL>& url_chain, 347 const SiteForCookies& site_for_cookies, 348 const std::optional<url::Origin>& initiator, 349 bool is_main_frame_navigation, 350 bool force_ignore_site_for_cookies); 351 352 // As above, but applying for scripts. `initiator` here should be the initiator 353 // used when fetching the document. 354 // If `force_ignore_site_for_cookies` is true, this returns SAME_SITE_STRICT. 355 NET_EXPORT CookieOptions::SameSiteCookieContext 356 ComputeSameSiteContextForScriptGet(const GURL& url, 357 const SiteForCookies& site_for_cookies, 358 const std::optional<url::Origin>& initiator, 359 bool force_ignore_site_for_cookies); 360 361 // Determines which of the cookies for the request URL can be set from a network 362 // response, with respect to the SameSite attribute. This will only return 363 // CROSS_SITE or SAME_SITE_LAX (cookie sets of SameSite=strict cookies are 364 // permitted in same contexts that sets of SameSite=lax cookies are). 365 // `url_chain` is a non-empty vector of URLs, the last of which is the current 366 // request URL. It represents the redirect chain of the current request. The 367 // redirect chain is used to calculate whether there has been a cross-site 368 // redirect. 369 // `is_main_frame_navigation` is whether the request was for a navigation that 370 // targets the main frame or top-level browsing context. Both SameSite=Lax and 371 // SameSite=Strict cookies may be set by any main frame navigation. 372 // If `force_ignore_site_for_cookies` is true, this returns SAME_SITE_LAX. 373 NET_EXPORT CookieOptions::SameSiteCookieContext 374 ComputeSameSiteContextForResponse(const std::vector<GURL>& url_chain, 375 const SiteForCookies& site_for_cookies, 376 const std::optional<url::Origin>& initiator, 377 bool is_main_frame_navigation, 378 bool force_ignore_site_for_cookies); 379 380 // Determines which of the cookies for `url` can be set from a script context, 381 // with respect to the SameSite attribute. This will only return CROSS_SITE or 382 // SAME_SITE_LAX (cookie sets of SameSite=strict cookies are permitted in same 383 // contexts that sets of SameSite=lax cookies are). 384 // If `force_ignore_site_for_cookies` is true, this returns SAME_SITE_LAX. 385 NET_EXPORT CookieOptions::SameSiteCookieContext 386 ComputeSameSiteContextForScriptSet(const GURL& url, 387 const SiteForCookies& site_for_cookies, 388 bool force_ignore_site_for_cookies); 389 390 // Determines which of the cookies for |url| can be accessed when fetching a 391 // subresources. This is either CROSS_SITE or SAME_SITE_STRICT, 392 // since the initiator for a subresource is the frame loading it. 393 NET_EXPORT CookieOptions::SameSiteCookieContext 394 // If |force_ignore_site_for_cookies| is true, this returns SAME_SITE_STRICT. 395 ComputeSameSiteContextForSubresource(const GURL& url, 396 const SiteForCookies& site_for_cookies, 397 bool force_ignore_site_for_cookies); 398 399 NET_EXPORT bool IsPortBoundCookiesEnabled(); 400 401 NET_EXPORT bool IsSchemeBoundCookiesEnabled(); 402 403 // Returns true if either portion of OBC is enabled. 404 NET_EXPORT bool IsOriginBoundCookiesPartiallyEnabled(); 405 406 NET_EXPORT bool IsTimeLimitedInsecureCookiesEnabled(); 407 408 // Returns whether the respective feature is enabled. 409 NET_EXPORT bool IsSchemefulSameSiteEnabled(); 410 411 // Computes the First-Party Sets metadata and cache match information. 412 // `isolation_info` must be fully populated. 413 // 414 // The result may be returned synchronously, or `callback` may be invoked 415 // asynchronously with the result. The callback will be invoked iff the return 416 // value is nullopt; i.e. a result will be provided via return value or 417 // callback, but not both, and not neither. 418 [[nodiscard]] NET_EXPORT std::optional< 419 std::pair<FirstPartySetMetadata, FirstPartySetsCacheFilter::MatchInfo>> 420 ComputeFirstPartySetMetadataMaybeAsync( 421 const SchemefulSite& request_site, 422 const IsolationInfo& isolation_info, 423 const CookieAccessDelegate* cookie_access_delegate, 424 base::OnceCallback<void(FirstPartySetMetadata, 425 FirstPartySetsCacheFilter::MatchInfo)> callback); 426 427 // Converts a string representing the http request method to its enum 428 // representation. 429 NET_EXPORT CookieOptions::SameSiteCookieContext::ContextMetadata::HttpMethod 430 HttpMethodStringToEnum(const std::string& in); 431 432 // Takes a CookieAccessResult and returns a bool, returning true if the 433 // CookieInclusionStatus in CookieAccessResult was set to "include", else 434 // returning false. 435 // 436 // Can be used with SetCanonicalCookie when you don't need to know why a cookie 437 // was blocked, only whether it was blocked. 438 NET_EXPORT bool IsCookieAccessResultInclude( 439 CookieAccessResult cookie_access_result); 440 441 // Turn a CookieAccessResultList into a CookieList by stripping out access 442 // results (for callers who only care about cookies). 443 NET_EXPORT CookieList 444 StripAccessResults(const CookieAccessResultList& cookie_access_result_list); 445 446 // Records port related metrics from Omnibox navigations. 447 NET_EXPORT void RecordCookiePortOmniboxHistograms(const GURL& url); 448 449 // Checks invariants that should be upheld w.r.t. the included and excluded 450 // cookies. Namely: the included cookies should be elements of 451 // `included_cookies`; excluded cookies should be elements of 452 // `excluded_cookies`; and included cookies should be in the correct sorted 453 // order. 454 NET_EXPORT void DCheckIncludedAndExcludedCookieLists( 455 const CookieAccessResultList& included_cookies, 456 const CookieAccessResultList& excluded_cookies); 457 458 // Returns the default third-party cookie blocking setting, which is false 459 // unless you enable ForceThirdPartyCookieBlocking with the command line switch 460 // --test-third-party-cookie-phaseout. 461 NET_EXPORT bool IsForceThirdPartyCookieBlockingEnabled(); 462 463 NET_EXPORT bool PartitionedCookiesDisabledByCommandLine(); 464 465 // Adds or removes the kStorageAccessGrantEligible override, as appropriate. 466 // Mutates `overrides` in place. 467 NET_EXPORT void AddOrRemoveStorageAccessApiOverride( 468 const GURL& url, 469 StorageAccessApiStatus api_status, 470 base::optional_ref<const url::Origin> request_initiator, 471 CookieSettingOverrides& overrides); 472 473 } // namespace cookie_util 474 475 } // namespace net 476 477 #endif // NET_COOKIES_COOKIE_UTIL_H_ 478