cookie_settings.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. // Copyright 2018 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. #include "services/network/cookie_settings.h"
  5. #include <functional>
  6. #include <iterator>
  7. #include "base/bind.h"
  8. #include "base/callback.h"
  9. #include "base/containers/contains.h"
  10. #include "base/metrics/histogram_macros.h"
  11. #include "base/ranges/algorithm.h"
  12. #include "base/stl_util.h"
  13. #include "components/content_settings/core/common/content_settings.h"
  14. #include "components/content_settings/core/common/cookie_settings_base.h"
  15. #include "net/base/features.h"
  16. #include "net/base/net_errors.h"
  17. #include "net/base/network_delegate.h"
  18. #include "net/cookies/canonical_cookie.h"
  19. #include "net/cookies/cookie_inclusion_status.h"
  20. #include "net/cookies/cookie_util.h"
  21. #include "net/cookies/static_cookie_policy.h"
  22. #include "third_party/abseil-cpp/absl/types/optional.h"
  23. #include "url/gurl.h"
  24. namespace network {
  25. namespace {
  26. using SamePartyCookieContextType = net::SamePartyContext::Type;
  27. bool IsExplicitSetting(const ContentSettingPatternSource& setting) {
  28. return !setting.primary_pattern.MatchesAllHosts() ||
  29. !setting.secondary_pattern.MatchesAllHosts();
  30. }
  31. const ContentSettingPatternSource* FindMatchingSetting(
  32. const GURL& primary_url,
  33. const GURL& secondary_url,
  34. const ContentSettingsForOneType& settings) {
  35. // We assume `settings` is sorted in order of precedence, so we use the first
  36. // matching rule we find.
  37. const auto& entry = base::ranges::find_if(
  38. settings, [&](const ContentSettingPatternSource& entry) {
  39. // The primary pattern is for the request URL; the secondary pattern
  40. // is for the first-party URL (which is the top-frame origin [if
  41. // available] or the site-for-cookies).
  42. return !entry.IsExpired() &&
  43. entry.primary_pattern.Matches(primary_url) &&
  44. entry.secondary_pattern.Matches(secondary_url);
  45. });
  46. return entry == settings.end() ? nullptr : &*entry;
  47. }
  48. } // namespace
  49. CookieSettings::CookieSettings() = default;
  50. CookieSettings::~CookieSettings() = default;
  51. DeleteCookiePredicate CookieSettings::CreateDeleteCookieOnExitPredicate()
  52. const {
  53. if (!HasSessionOnlyOrigins())
  54. return DeleteCookiePredicate();
  55. return base::BindRepeating(&CookieSettings::ShouldDeleteCookieOnExit,
  56. base::Unretained(this),
  57. std::cref(content_settings_));
  58. }
  59. ContentSetting CookieSettings::GetSettingForLegacyCookieAccess(
  60. const std::string& cookie_domain) const {
  61. // Default to match what was registered in the ContentSettingsRegistry.
  62. ContentSetting setting = CONTENT_SETTING_BLOCK;
  63. if (settings_for_legacy_cookie_access_.empty())
  64. return setting;
  65. // If there are no domain-specific settings, return early to avoid the cost of
  66. // constructing a GURL to match against.
  67. if (base::ranges::all_of(settings_for_legacy_cookie_access_,
  68. [](const ContentSettingPatternSource& entry) {
  69. return entry.primary_pattern.MatchesAllHosts();
  70. })) {
  71. // Take the first entry because we know all entries match any host.
  72. setting = settings_for_legacy_cookie_access_[0].GetContentSetting();
  73. DCHECK(IsValidSettingForLegacyAccess(setting));
  74. return setting;
  75. }
  76. // The content setting patterns are treated as domains, not URLs, so the
  77. // scheme is irrelevant (so we can just arbitrarily pass false).
  78. GURL cookie_domain_url = net::cookie_util::CookieOriginToURL(
  79. cookie_domain, false /* secure scheme */);
  80. for (const auto& entry : settings_for_legacy_cookie_access_) {
  81. // TODO(crbug.com/1015611): This should ignore scheme and port, but
  82. // currently takes them into account. It says in the policy description that
  83. // specifying a scheme or port in the pattern may lead to undefined
  84. // behavior, but this is not ideal.
  85. if (entry.primary_pattern.Matches(cookie_domain_url)) {
  86. DCHECK(IsValidSettingForLegacyAccess(entry.GetContentSetting()));
  87. return entry.GetContentSetting();
  88. }
  89. }
  90. return setting;
  91. }
  92. bool CookieSettings::ShouldIgnoreSameSiteRestrictions(
  93. const GURL& url,
  94. const net::SiteForCookies& site_for_cookies) const {
  95. return base::Contains(secure_origin_cookies_allowed_schemes_,
  96. site_for_cookies.scheme()) &&
  97. url.SchemeIsCryptographic();
  98. }
  99. bool CookieSettings::IsCookieAccessible(
  100. const net::CanonicalCookie& cookie,
  101. const GURL& url,
  102. const net::SiteForCookies& site_for_cookies,
  103. const absl::optional<url::Origin>& top_frame_origin) const {
  104. return IsHypotheticalCookieAllowed(
  105. GetCookieSettingWithMetadata(
  106. url,
  107. GetFirstPartyURL(site_for_cookies,
  108. base::OptionalOrNullptr(top_frame_origin)),
  109. IsThirdPartyRequest(url, site_for_cookies), QueryReason::kCookies),
  110. cookie.IsSameParty(), cookie.IsPartitioned(), /*record_metrics=*/true);
  111. }
  112. bool CookieSettings::ShouldAlwaysAllowCookies(
  113. const GURL& url,
  114. const GURL& first_party_url) const {
  115. return (base::Contains(secure_origin_cookies_allowed_schemes_,
  116. first_party_url.scheme()) &&
  117. url.SchemeIsCryptographic()) ||
  118. (base::Contains(matching_scheme_cookies_allowed_schemes_,
  119. url.scheme()) &&
  120. url.SchemeIs(first_party_url.scheme_piece()));
  121. }
  122. net::NetworkDelegate::PrivacySetting CookieSettings::IsPrivacyModeEnabled(
  123. const GURL& url,
  124. const net::SiteForCookies& site_for_cookies,
  125. const absl::optional<url::Origin>& top_frame_origin,
  126. SamePartyCookieContextType same_party_cookie_context_type) const {
  127. // PrivacySetting should be kStateDisallowed iff no cookies should ever
  128. // be sent on this request. E.g.:
  129. //
  130. // * if cookie settings block cookies on this site or for this URL; or
  131. //
  132. // * if cookie settings block 3P cookies, the context is cross-party, and
  133. // content settings blocks the 1P from using cookies; or
  134. //
  135. // * if cookie settings block 3P cookies, and the context is same-party, but
  136. // SameParty cookies aren't considered 1P.
  137. //
  138. // PrivacySetting should be kPartitionedStateAllowedOnly iff the request is
  139. // cross-party, cookie settings block 3P cookies, and content settings allows
  140. // the 1P to use cookies.
  141. //
  142. // Otherwise, the PrivacySetting should be kStateAllowed.
  143. //
  144. // We don't record metrics here, since this isn't actually accessing a cookie.
  145. CookieSettingWithMetadata metadata = GetCookieSettingWithMetadata(
  146. url, site_for_cookies, base::OptionalOrNullptr(top_frame_origin),
  147. QueryReason::kCookies);
  148. if (IsHypotheticalCookieAllowed(metadata,
  149. same_party_cookie_context_type ==
  150. SamePartyCookieContextType::kSameParty,
  151. /*is_partitioned*/ false,
  152. /*record_metrics=*/false)) {
  153. return net::NetworkDelegate::PrivacySetting::kStateAllowed;
  154. }
  155. // No unpartitioned cookie should be sent on this request. The only other
  156. // options are to block all cookies, or allow just partitioned cookies.
  157. switch (metadata.third_party_blocking_outcome) {
  158. case ThirdPartyBlockingOutcome::kIrrelevant:
  159. [[fallthrough]];
  160. case ThirdPartyBlockingOutcome::kAllStateDisallowed:
  161. return net::NetworkDelegate::PrivacySetting::kStateDisallowed;
  162. case ThirdPartyBlockingOutcome::kPartitionedStateAllowed:
  163. return net::NetworkDelegate::PrivacySetting::kPartitionedStateAllowedOnly;
  164. }
  165. }
  166. bool CookieSettings::BlockDueToThirdPartyCookieBlockingSetting(
  167. bool is_third_party_request,
  168. const GURL& url,
  169. const GURL& first_party_url,
  170. ContentSetting cookie_setting,
  171. QueryReason query_reason) const {
  172. if (block_third_party_cookies_ && is_third_party_request &&
  173. !base::Contains(third_party_cookies_allowed_schemes_,
  174. first_party_url.scheme())) {
  175. if (ShouldConsiderStorageAccessGrants(query_reason)) {
  176. // See if a Storage Access permission grant can unblock.
  177. if (const ContentSettingPatternSource* match =
  178. FindMatchingSetting(url, first_party_url, storage_access_grants_);
  179. match && match->GetContentSetting() == CONTENT_SETTING_ALLOW) {
  180. FireStorageAccessHistogram(net::cookie_util::StorageAccessResult::
  181. ACCESS_ALLOWED_STORAGE_ACCESS_GRANT);
  182. return false;
  183. }
  184. }
  185. FireStorageAccessHistogram(
  186. net::cookie_util::StorageAccessResult::ACCESS_BLOCKED);
  187. return true;
  188. }
  189. // Cookies aren't blocked solely due to the third-party-cookie blocking
  190. // setting, but they still may be blocked due to a global default. So we
  191. // have to check what the setting is here.
  192. FireStorageAccessHistogram(
  193. cookie_setting == CONTENT_SETTING_BLOCK
  194. ? net::cookie_util::StorageAccessResult::ACCESS_BLOCKED
  195. : net::cookie_util::StorageAccessResult::ACCESS_ALLOWED);
  196. return false;
  197. }
  198. CookieSettings::ThirdPartyBlockingOutcome
  199. CookieSettings::GetThirdPartyBlockingScope(const GURL& first_party_url) const {
  200. // If cookies are allowed for the first-party URL then we allow
  201. // partitioned cross-site cookies.
  202. if (const ContentSettingPatternSource* match = FindMatchingSetting(
  203. first_party_url, first_party_url, content_settings_);
  204. !match || match->GetContentSetting() == CONTENT_SETTING_ALLOW) {
  205. return ThirdPartyBlockingOutcome::kPartitionedStateAllowed;
  206. }
  207. return ThirdPartyBlockingOutcome::kAllStateDisallowed;
  208. }
  209. CookieSettings::CookieSettingWithMetadata
  210. CookieSettings::GetCookieSettingWithMetadata(const GURL& url,
  211. const GURL& first_party_url,
  212. bool is_third_party_request,
  213. QueryReason query_reason) const {
  214. if (ShouldAlwaysAllowCookies(url, first_party_url)) {
  215. return {
  216. /*cookie_setting=*/CONTENT_SETTING_ALLOW,
  217. /*third_party_blocking_outcome=*/
  218. ThirdPartyBlockingOutcome::kIrrelevant,
  219. };
  220. }
  221. // Default to allowing cookies.
  222. ContentSetting cookie_setting = CONTENT_SETTING_ALLOW;
  223. ThirdPartyBlockingOutcome third_party_blocking_outcome =
  224. ThirdPartyBlockingOutcome::kIrrelevant;
  225. bool found_explicit_setting = false;
  226. if (const ContentSettingPatternSource* match =
  227. FindMatchingSetting(url, first_party_url, content_settings_);
  228. match) {
  229. cookie_setting = match->GetContentSetting();
  230. found_explicit_setting = IsExplicitSetting(*match);
  231. }
  232. if (cookie_setting != CONTENT_SETTING_BLOCK && !found_explicit_setting) {
  233. if (BlockDueToThirdPartyCookieBlockingSetting(
  234. is_third_party_request, url, first_party_url, cookie_setting,
  235. query_reason)) {
  236. cookie_setting = CONTENT_SETTING_BLOCK;
  237. third_party_blocking_outcome =
  238. GetThirdPartyBlockingScope(first_party_url);
  239. }
  240. } else {
  241. FireStorageAccessHistogram(
  242. cookie_setting == CONTENT_SETTING_BLOCK
  243. ? net::cookie_util::StorageAccessResult::ACCESS_BLOCKED
  244. : net::cookie_util::StorageAccessResult::ACCESS_ALLOWED);
  245. }
  246. return {cookie_setting, third_party_blocking_outcome};
  247. }
  248. CookieSettings::CookieSettingWithMetadata
  249. CookieSettings::GetCookieSettingWithMetadata(
  250. const GURL& url,
  251. const net::SiteForCookies& site_for_cookies,
  252. const url::Origin* top_frame_origin,
  253. QueryReason query_reason) const {
  254. return GetCookieSettingWithMetadata(
  255. url, GetFirstPartyURL(site_for_cookies, top_frame_origin),
  256. IsThirdPartyRequest(url, site_for_cookies), query_reason);
  257. }
  258. ContentSetting CookieSettings::GetCookieSettingInternal(
  259. const GURL& url,
  260. const GURL& first_party_url,
  261. bool is_third_party_request,
  262. content_settings::SettingSource* source,
  263. QueryReason query_reason) const {
  264. return GetCookieSettingWithMetadata(url, first_party_url,
  265. is_third_party_request, query_reason)
  266. .cookie_setting;
  267. }
  268. bool CookieSettings::AnnotateAndMoveUserBlockedCookies(
  269. const GURL& url,
  270. const net::SiteForCookies& site_for_cookies,
  271. const url::Origin* top_frame_origin,
  272. net::CookieAccessResultList& maybe_included_cookies,
  273. net::CookieAccessResultList& excluded_cookies) const {
  274. const CookieSettingWithMetadata setting_with_metadata =
  275. GetCookieSettingWithMetadata(url, site_for_cookies, top_frame_origin,
  276. QueryReason::kCookies);
  277. if (IsAllowed(setting_with_metadata.cookie_setting))
  278. return true;
  279. // Add the `EXCLUDE_USER_PREFERENCES` `ExclusionReason` for cookies that ought
  280. // to be blocked, and find any cookies that should still be allowed.
  281. bool is_any_allowed = false;
  282. for (net::CookieWithAccessResult& cookie : maybe_included_cookies) {
  283. if (IsCookieAllowed(setting_with_metadata, cookie)) {
  284. is_any_allowed = true;
  285. } else {
  286. cookie.access_result.status.AddExclusionReason(
  287. net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES);
  288. }
  289. }
  290. for (net::CookieWithAccessResult& cookie : excluded_cookies) {
  291. if (!IsCookieAllowed(setting_with_metadata, cookie)) {
  292. cookie.access_result.status.AddExclusionReason(
  293. net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES);
  294. }
  295. }
  296. const auto to_be_moved = base::ranges::stable_partition(
  297. maybe_included_cookies, [](const net::CookieWithAccessResult& cookie) {
  298. return cookie.access_result.status.IsInclude();
  299. });
  300. excluded_cookies.insert(
  301. excluded_cookies.end(), std::make_move_iterator(to_be_moved),
  302. std::make_move_iterator(maybe_included_cookies.end()));
  303. maybe_included_cookies.erase(to_be_moved, maybe_included_cookies.end());
  304. net::cookie_util::DCheckIncludedAndExcludedCookieLists(maybe_included_cookies,
  305. excluded_cookies);
  306. return is_any_allowed;
  307. }
  308. bool CookieSettings::IsCookieAllowed(
  309. const CookieSettingWithMetadata& setting_with_metadata,
  310. const net::CookieWithAccessResult& cookie) const {
  311. return IsHypotheticalCookieAllowed(
  312. setting_with_metadata,
  313. cookie.cookie.IsSameParty() &&
  314. !cookie.access_result.status.HasExclusionReason(
  315. net::CookieInclusionStatus::
  316. EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT),
  317. cookie.cookie.IsPartitioned(),
  318. /*record_metrics=*/true);
  319. }
  320. bool CookieSettings::IsAllowedSamePartyCookie(
  321. bool is_same_party,
  322. ThirdPartyBlockingOutcome third_party_blocking_outcome,
  323. bool record_metrics) const {
  324. bool blocked_by_3p_but_same_party =
  325. is_same_party &&
  326. third_party_blocking_outcome != ThirdPartyBlockingOutcome::kIrrelevant;
  327. if (record_metrics && blocked_by_3p_but_same_party) {
  328. UMA_HISTOGRAM_BOOLEAN(
  329. "Cookie.SameParty.BlockedByThirdPartyCookieBlockingSetting",
  330. !sameparty_cookies_considered_first_party_);
  331. }
  332. return sameparty_cookies_considered_first_party_ &&
  333. blocked_by_3p_but_same_party;
  334. }
  335. // static
  336. bool CookieSettings::IsAllowedPartitionedCookie(
  337. bool is_partitioned,
  338. ThirdPartyBlockingOutcome third_party_blocking_outcome) {
  339. return is_partitioned &&
  340. third_party_blocking_outcome ==
  341. ThirdPartyBlockingOutcome::kPartitionedStateAllowed;
  342. }
  343. bool CookieSettings::IsHypotheticalCookieAllowed(
  344. const CookieSettingWithMetadata& setting_with_metadata,
  345. bool is_same_party,
  346. bool is_partitioned,
  347. bool record_metrics) const {
  348. DCHECK(!is_partitioned || !is_same_party);
  349. return IsAllowed(setting_with_metadata.cookie_setting) ||
  350. IsAllowedSamePartyCookie(
  351. is_same_party, setting_with_metadata.third_party_blocking_outcome,
  352. record_metrics) ||
  353. IsAllowedPartitionedCookie(
  354. is_partitioned,
  355. setting_with_metadata.third_party_blocking_outcome);
  356. }
  357. bool CookieSettings::HasSessionOnlyOrigins() const {
  358. return base::ranges::any_of(content_settings_, [](const auto& entry) {
  359. return entry.GetContentSetting() == CONTENT_SETTING_SESSION_ONLY;
  360. });
  361. }
  362. } // namespace network