blob: 13e0fce7403d26956aaca8a4c29e8d844b512177 [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2020 The Chromium Authors
Alexander Timin1cc31f42020-05-12 16:26:012// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
danakjc492bf82020-09-09 20:02:445#include "content/browser/renderer_host/cookie_utils.h"
Alexander Timin1cc31f42020-05-12 16:26:016
Peter Kasting1557e5f2025-01-28 01:14:087#include <algorithm>
Sandor Major7c3e612f2023-12-01 20:48:088#include <cstddef>
9#include <ostream>
10#include <string>
11
12#include "base/feature_list.h"
13#include "base/logging.h"
sbingler8e26e212023-09-27 23:23:2714#include "base/strings/string_util.h"
Shuran Huang7a6757c22024-04-17 15:17:3915#include "base/unguessable_token.h"
Alexander Timin1cc31f42020-05-12 16:26:0116#include "content/browser/devtools/devtools_instrumentation.h"
Sandor Major7c3e612f2023-12-01 20:48:0817#include "content/browser/navigation_or_document_handle.h"
18#include "content/browser/renderer_host/navigation_request.h"
danakjc492bf82020-09-09 20:02:4419#include "content/browser/renderer_host/render_frame_host_impl.h"
Alexander Timin1cc31f42020-05-12 16:26:0120#include "content/public/browser/browser_context.h"
21#include "content/public/browser/cookie_access_details.h"
Sandor Major7c3e612f2023-12-01 20:48:0822#include "content/public/browser/legacy_tech_cookie_issue_details.h"
Alexander Timin1cc31f42020-05-12 16:26:0123#include "content/public/common/content_client.h"
Sandor Major7c3e612f2023-12-01 20:48:0824#include "content/public/common/content_features.h"
Chris Fredrickson6639c0a42025-03-27 21:50:2825#include "net/cookies/cookie_constants.h"
Jihwan Marc Kim3e132f12020-05-20 17:33:1926#include "net/cookies/cookie_inclusion_status.h"
Chris Fredrickson6639c0a42025-03-27 21:50:2827#include "net/cookies/cookie_setting_override.h"
sbingler870b63f2023-04-25 16:47:5828#include "services/metrics/public/cpp/metrics_utils.h"
Alexander Timin1cc31f42020-05-12 16:26:0129#include "services/metrics/public/cpp/ukm_builders.h"
Chris Fredrickson6639c0a42025-03-27 21:50:2830#include "third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom-shared.h"
Sandor Major7c3e612f2023-12-01 20:48:0831#include "url/gurl.h"
Alexander Timin1cc31f42020-05-12 16:26:0132
33namespace content {
34
35namespace {
36
sbingler8e26e212023-09-27 23:23:2737void PotentiallyRecordNonAsciiCookieNameValue(
38 RenderFrameHost* rfh,
39 CookieAccessDetails::Type access_type,
40 const std::string& name,
41 const std::string& value) {
42 CHECK(rfh);
43
44 if (access_type != CookieAccessDetails::Type::kChange) {
45 return;
46 }
47
48 // Our data collection policy disallows collecting UKMs while prerendering.
49 // See //content/browser/preloading/prerender/README.md and ask the team to
50 // explore options to record data for prerendering pages if we need to
51 // support the case.
52 if (rfh->IsInLifecycleState(RenderFrameHost::LifecycleState::kPrerendering)) {
53 return;
54 }
55
56 bool name_has_non_ascii = !base::IsStringASCII(name);
57 bool value_has_non_ascii = !base::IsStringASCII(value);
58
59 if (name_has_non_ascii || value_has_non_ascii) {
60 ukm::SourceId source_id = rfh->GetPageUkmSourceId();
61
62 auto event = ukm::builders::CookieHasNonAsciiCharacter(source_id);
63
64 // The event itself is what we're interested in, the value of "true" here
65 // can be ignored.
66 if (name_has_non_ascii) {
67 event.SetName(true);
68 }
69
70 if (value_has_non_ascii) {
71 event.SetValue(true);
72 }
73
74 event.Record(ukm::UkmRecorder::Get());
75 }
76}
77
amarjotgilld43eb5d12024-11-11 17:53:3678void PotentiallyRecordCookieOriginMismatch(
79 RenderFrameHost* rfh,
80 CookieAccessDetails::Type access_type,
81 const net::CookieInclusionStatus& status) {
82 CHECK(rfh);
83
84 if (access_type != CookieAccessDetails::Type::kRead) {
85 return;
86 }
87
88 // Our data collection policy disallows collecting UKMs while prerendering.
89 // See //content/browser/preloading/prerender/README.md and ask the team to
90 // explore options to record data for prerendering pages if we need to
91 // support the case.
92 if (rfh->IsInLifecycleState(RenderFrameHost::LifecycleState::kPrerendering)) {
93 return;
94 }
95 const bool port_mismatch =
Chris Fredrickson66f167f2025-01-21 18:18:2096 status.HasWarningReason(
97 net::CookieInclusionStatus::WarningReason::WARN_PORT_MISMATCH) ||
amarjotgilld43eb5d12024-11-11 17:53:3698 status.HasExclusionReason(
Chris Fredrickson0a9673e2025-01-21 16:45:1499 net::CookieInclusionStatus::ExclusionReason::EXCLUDE_PORT_MISMATCH);
amarjotgilld43eb5d12024-11-11 17:53:36100
101 const bool scheme_mismatch =
102 status.HasWarningReason(
Chris Fredrickson66f167f2025-01-21 18:18:20103 net::CookieInclusionStatus::WarningReason::WARN_SCHEME_MISMATCH) ||
amarjotgilld43eb5d12024-11-11 17:53:36104 status.HasExclusionReason(
Chris Fredrickson0a9673e2025-01-21 16:45:14105 net::CookieInclusionStatus::ExclusionReason::EXCLUDE_SCHEME_MISMATCH);
amarjotgilld43eb5d12024-11-11 17:53:36106
107 if (port_mismatch || scheme_mismatch) {
108 ukm::SourceId source_id = rfh->GetPageUkmSourceId();
109
110 auto event = ukm::builders::Cookies_Blocked_DueToOriginMismatch(source_id);
111
112 // The event itself is what we're interested in, the value of "true" here
113 // can be ignored.
114 if (port_mismatch) {
115 event.SetPortMismatch(true);
116 }
117
118 if (scheme_mismatch) {
119 event.SetSchemeMismatch(true);
120 }
121
122 event.Record(ukm::UkmRecorder::Get());
123 }
124}
125
selya19cc0d22024-12-10 20:36:07126void RecordCookiesExemptedByTopLevelStorage(ukm::SourceId source_id,
127 int affected_cookies_in_request) {
128 ukm::builders::RequestStorageAccessFor_TopLevelStorageIsExemptionReason(
129 source_id)
130 .SetNumberOfCookies(ukm::GetExponentialBucketMin(
131 affected_cookies_in_request, /*bucket_spacing=*/2.0))
132 .Record(ukm::UkmRecorder::Get());
133}
134
selya7d96d6182024-04-22 11:35:51135// Relies on checks in RecordPartitionedCookiesUKMs to confirm that that the
136// cookie name is not "receive-cookie-deprecation", that cookie is first party
137// partitioned and the RenderFrameHost is not prerendering.
selya778265bc2023-10-23 14:37:55138void RecordFirstPartyPartitionedCookieCrossSiteContextUKM(
139 RenderFrameHostImpl* render_frame_host_impl,
selya7d96d6182024-04-22 11:35:51140 const net::CanonicalCookie& cookie,
141 const ukm::SourceId& source_id) {
selya778265bc2023-10-23 14:37:55142 // Same-site embed with cross-site ancestors (ABA embeds) have a null site
143 // for cookies since it is a cross-site context. If the result of
144 // ComputeSiteForCookies is first-party that means we are not in an ABA
145 // embedded context.
selya01be4aa22024-01-25 18:36:24146 bool has_cross_site_ancestor =
147 !render_frame_host_impl->ComputeSiteForCookies().IsFirstParty(
selya778265bc2023-10-23 14:37:55148 GURL(base::StrCat({url::kHttpsScheme, url::kStandardSchemeSeparator,
selya01be4aa22024-01-25 18:36:24149 cookie.DomainWithoutDot()})));
selya778265bc2023-10-23 14:37:55150
selya7d96d6182024-04-22 11:35:51151 ukm::builders::Cookies_FirstPartyPartitionedInCrossSiteContextV3(source_id)
selya01be4aa22024-01-25 18:36:24152 .SetCookiePresent(has_cross_site_ancestor)
selya778265bc2023-10-23 14:37:55153 .Record(ukm::UkmRecorder::Get());
154}
155
selya7d96d6182024-04-22 11:35:51156// Relies on checks in RecordPartitionedCookiesUKMs to confirm that that the
157// cookie is partitioned, the cookie name is not
158// "receive-cookie-deprecation" and the RenderFrameHost is not prerendering.
159void RecordPartitionedCookieUseV2UKM(RenderFrameHost* rfh,
160 const net::CanonicalCookie& cookie,
161 const ukm::SourceId& source_id) {
162 ukm::builders::PartitionedCookiePresentV2(source_id)
163 .SetPartitionedCookiePresentV2(true)
164 .Record(ukm::UkmRecorder::Get());
165}
166
167void RecordPartitionedCookiesUKMs(RenderFrameHostImpl* render_frame_host_impl,
168 const net::CanonicalCookie& cookie) {
selya27d093e2023-08-02 22:20:00169 // Our data collection policy disallows collecting UKMs while prerendering.
170 // See //content/browser/preloading/prerender/README.md and ask the team to
171 // explore options to record data for prerendering pages if we need to
172 // support the case.
selya7d96d6182024-04-22 11:35:51173 if (render_frame_host_impl->IsInLifecycleState(
174 RenderFrameHost::LifecycleState::kPrerendering)) {
selya27d093e2023-08-02 22:20:00175 return;
176 }
selya27d093e2023-08-02 22:20:00177
selya7d96d6182024-04-22 11:35:51178 // Cookies_FirstPartyPartitionedInCrossSiteContextV3 and
179 // PartitionedCookiePresentV2 both measure cookies
180 // without the name of 'receive-cookie-deprecation'. Return here to ensure
181 // that the metrics do not include those cookies.
182 if (cookie.Name() == "receive-cookie-deprecation") {
183 return;
184 }
185
186 ukm::SourceId source_id = render_frame_host_impl->GetPageUkmSourceId();
187
188 if (cookie.IsFirstPartyPartitioned()) {
189 RecordFirstPartyPartitionedCookieCrossSiteContextUKM(render_frame_host_impl,
190 cookie, source_id);
191 }
192
193 RecordPartitionedCookieUseV2UKM(render_frame_host_impl, cookie, source_id);
selya27d093e2023-08-02 22:20:00194}
195
sbingler870b63f2023-04-25 16:47:58196void RecordRedirectContextDowngradeUKM(RenderFrameHost* rfh,
197 CookieAccessDetails::Type access_type,
198 const net::CanonicalCookie& cookie,
199 const GURL& url) {
200 CHECK(rfh);
Takashi Toyoshimad540b932023-06-30 02:30:27201
202 // Our data collection policy disallows collecting UKMs while prerendering.
203 // See //content/browser/preloading/prerender/README.md and ask the team to
204 // explore options to record data for prerendering pages if we need to
205 // support the case.
206 if (rfh->IsInLifecycleState(RenderFrameHost::LifecycleState::kPrerendering)) {
207 return;
208 }
209
sbingler870b63f2023-04-25 16:47:58210 ukm::SourceId source_id = rfh->GetPageUkmSourceId();
211
212 int64_t samesite_value = static_cast<int64_t>(cookie.SameSite());
213 if (access_type == CookieAccessDetails::Type::kRead) {
214 base::TimeDelta cookie_age = base::Time::Now() - cookie.CreationDate();
215
216 ukm::builders::SamesiteRedirectContextDowngrade(source_id)
217 .SetSamesiteValueReadPerCookie(samesite_value)
218 .SetAgePerCookie(
219 ukm::GetExponentialBucketMinForUserTiming(cookie_age.InMinutes()))
220 .Record(ukm::UkmRecorder::Get());
221 } else {
222 CHECK(access_type == CookieAccessDetails::Type::kChange);
223 ukm::builders::SamesiteRedirectContextDowngrade(source_id)
224 .SetSamesiteValueWritePerCookie(samesite_value)
225 .Record(ukm::UkmRecorder::Get());
226 }
227}
228
229void RecordSchemefulContextDowngradeUKM(
230 RenderFrameHost* rfh,
231 CookieAccessDetails::Type access_type,
232 const net::CookieInclusionStatus& status,
233 const GURL& url) {
234 CHECK(rfh);
Takashi Toyoshimad540b932023-06-30 02:30:27235
236 // Our data collection policy disallows collecting UKMs while prerendering.
237 // See //content/browser/preloading/prerender/README.md and ask the team to
238 // explore options to record data for prerendering pages if we need to
239 // support the case.
240 if (rfh->IsInLifecycleState(RenderFrameHost::LifecycleState::kPrerendering)) {
241 return;
242 }
243
Alexander Timin1cc31f42020-05-12 16:26:01244 ukm::SourceId source_id = rfh->GetPageUkmSourceId();
245
Lei Zhang3ab30192022-08-15 19:52:20246 auto downgrade_metric =
247 static_cast<int64_t>(status.GetBreakingDowngradeMetricsEnumValue(url));
Alexander Timin1cc31f42020-05-12 16:26:01248 if (access_type == CookieAccessDetails::Type::kRead) {
249 ukm::builders::SchemefulSameSiteContextDowngrade(source_id)
Lei Zhang3ab30192022-08-15 19:52:20250 .SetRequestPerCookie(downgrade_metric)
Alexander Timin1cc31f42020-05-12 16:26:01251 .Record(ukm::UkmRecorder::Get());
252 } else {
sbingler870b63f2023-04-25 16:47:58253 CHECK(access_type == CookieAccessDetails::Type::kChange);
Alexander Timin1cc31f42020-05-12 16:26:01254 ukm::builders::SchemefulSameSiteContextDowngrade(source_id)
Lei Zhang3ab30192022-08-15 19:52:20255 .SetResponsePerCookie(downgrade_metric)
Alexander Timin1cc31f42020-05-12 16:26:01256 .Record(ukm::UkmRecorder::Get());
257 }
258}
259
Simon Zünd657178e2021-05-27 06:19:55260bool ShouldReportDevToolsIssueForStatus(
261 const net::CookieInclusionStatus& status) {
262 return status.ShouldWarn() ||
Chris Fredrickson0a9673e2025-01-21 16:45:14263 status.HasExclusionReason(net::CookieInclusionStatus::ExclusionReason::
264 EXCLUDE_DOMAIN_NON_ASCII) ||
265 status.HasExclusionReason(net::CookieInclusionStatus::ExclusionReason::
266 EXCLUDE_PORT_MISMATCH) ||
267 status.HasExclusionReason(net::CookieInclusionStatus::ExclusionReason::
268 EXCLUDE_SCHEME_MISMATCH) ||
Simon Zünd657178e2021-05-27 06:19:55269 status.HasExclusionReason(
Chris Fredrickson0a9673e2025-01-21 16:45:14270 net::CookieInclusionStatus::ExclusionReason::
Shuran Huangdc0b8d82023-09-19 14:49:30271 EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET) ||
Chris Fredrickson0a9673e2025-01-21 16:45:14272 status.HasExclusionReason(net::CookieInclusionStatus::ExclusionReason::
273 EXCLUDE_THIRD_PARTY_PHASEOUT) ||
Joshua Thomas48f0eea2024-09-17 02:25:52274 status.exemption_reason() ==
275 net::CookieInclusionStatus::ExemptionReason::k3PCDMetadata ||
276 status.exemption_reason() ==
277 net::CookieInclusionStatus::ExemptionReason::k3PCDHeuristics;
Simon Zünd657178e2021-05-27 06:19:55278}
279
Chris Fredrickson6639c0a42025-03-27 21:50:28280bool IsCrossOriginSameSiteNetworkAccessWithStorageAccessEligible(
281 const network::mojom::CookieAccessDetailsPtr& cookie_details) {
282 if (!cookie_details->frame_origin ||
283 !cookie_details->cookie_setting_overrides.Has(
284 net::CookieSettingOverride::kStorageAccessGrantEligible)) {
285 // `frame_origin` is unset for script accesses, and network accesses whose
286 // IsolationInfo's `frame_origin` was nullptr.
287 return false;
288 }
289 const url::Origin origin = url::Origin::Create(cookie_details->url);
290 return !origin.IsSameOriginWith(cookie_details->frame_origin.value()) &&
291 net::SchemefulSite::IsSameSite(origin,
292 cookie_details->frame_origin.value());
293}
294
Sandor Major77742112025-01-14 18:36:11295} // namespace
296
297void SplitCookiesIntoAllowedAndBlocked(
298 const network::mojom::CookieAccessDetailsPtr& cookie_details,
Ryan Tarpine60f087a92025-03-10 14:46:59299 CookieAccessDetails::Source source,
Sandor Major77742112025-01-14 18:36:11300 CookieAccessDetails* allowed,
301 CookieAccessDetails* blocked) {
302 // For some cases `site_for_cookies` representative url is empty when
303 // OnCookieAccess is triggered for a third party. For example iframe third
304 // party accesses cookies when TPCD Metadata allows third party cookie access.
305 //
306 // Make `first_party_url` considering both `top_frame_origin` and
307 // `site_for_cookies` which is similar with GetFirstPartyURL() in
308 // components/content_settings/core/common/cookie_settings_base.h.
309 // If the `top_frame_origin` is non-opaque, it is chosen; otherwise, the
310 // `site_for_cookies` representative url is used.
311 const GURL first_party_url =
312 cookie_details->top_frame_origin.opaque()
313 ? cookie_details->site_for_cookies.RepresentativeUrl()
314 : cookie_details->top_frame_origin.GetURL();
315
316 *allowed = CookieAccessDetails({cookie_details->type,
317 cookie_details->url,
318 first_party_url,
319 {},
320 /* blocked_by_policy=*/false,
321 cookie_details->is_ad_tagged,
322 cookie_details->cookie_setting_overrides,
Ryan Tarpine60f087a92025-03-10 14:46:59323 cookie_details->site_for_cookies,
324 source});
Peter Kasting1557e5f2025-01-28 01:14:08325 int allowed_count = std::ranges::count_if(
Sandor Major77742112025-01-14 18:36:11326 cookie_details->cookie_list,
327 [](const network::mojom::CookieOrLineWithAccessResultPtr&
328 cookie_and_access_result) {
329 // "Included" cookies have no exclusion reasons so we don't also have to
Chris Fredrickson0a9673e2025-01-21 16:45:14330 // check for
331 // !(net::CookieInclusionStatus::ExclusionReason::EXCLUDE_USER_PREFERENCES).
Sandor Major77742112025-01-14 18:36:11332 return cookie_and_access_result->access_result.status.IsInclude();
333 });
334 allowed->cookie_access_result_list.reserve(allowed_count);
335
336 *blocked = CookieAccessDetails({cookie_details->type,
337 cookie_details->url,
338 first_party_url,
339 {},
340 /* blocked_by_policy=*/true,
341 cookie_details->is_ad_tagged,
342 cookie_details->cookie_setting_overrides,
Ryan Tarpine60f087a92025-03-10 14:46:59343 cookie_details->site_for_cookies,
344 source});
Peter Kasting1557e5f2025-01-28 01:14:08345 int blocked_count = std::ranges::count_if(
Sandor Major77742112025-01-14 18:36:11346 cookie_details->cookie_list,
347 [](const network::mojom::CookieOrLineWithAccessResultPtr&
348 cookie_and_access_result) {
349 return cookie_and_access_result->access_result.status
350 .ExcludedByUserPreferencesOrTPCD();
351 });
352 blocked->cookie_access_result_list.reserve(blocked_count);
353
354 for (const auto& cookie_and_access_result : cookie_details->cookie_list) {
355 if (cookie_and_access_result->access_result.status
356 .ExcludedByUserPreferencesOrTPCD()) {
357 blocked->cookie_access_result_list.emplace_back(
358 std::move(cookie_and_access_result->cookie_or_line->get_cookie()),
359 cookie_and_access_result->access_result);
360 } else if (cookie_and_access_result->access_result.status.IsInclude()) {
361 allowed->cookie_access_result_list.emplace_back(
362 std::move(cookie_and_access_result->cookie_or_line->get_cookie()),
363 cookie_and_access_result->access_result);
364 }
365 }
Sandor Major7c3e612f2023-12-01 20:48:08366}
Sandor Major7c3e612f2023-12-01 20:48:08367
368// Logs cookie issues to DevTools Issues Panel and logs events to UseCounters
Shuran Huang8fa11c72023-12-04 16:53:44369// and UKM for a single cookie-accessed event.
Alison Gale770f3fc2024-04-27 00:39:58370// TODO(crbug.com/40632967): Remove when no longer needed.
Sandor Major77742112025-01-14 18:36:11371void EmitCookieWarningsAndMetrics(
Alexander Timin1cc31f42020-05-12 16:26:01372 RenderFrameHostImpl* rfh,
373 const network::mojom::CookieAccessDetailsPtr& cookie_details) {
374 RenderFrameHostImpl* root_frame_host = rfh->GetMainFrame();
375
Sreeja Kamishettye49854f82021-06-02 00:52:03376 if (!root_frame_host->IsActive())
Alexander Timin1cc31f42020-05-12 16:26:01377 return;
378
379 bool samesite_treated_as_lax_cookies = false;
380 bool samesite_none_insecure_cookies = false;
Alexander Timin1cc31f42020-05-12 16:26:01381 bool breaking_context_downgrade = false;
Lily Chenc4423c02021-03-11 16:02:02382 bool lax_allow_unsafe_cookies = false;
Alexander Timin1cc31f42020-05-12 16:26:01383
Lily Chen2db3a422021-07-20 18:02:25384 bool samesite_cookie_inclusion_changed_by_cross_site_redirect = false;
385
Dylan Cutler8d5f8912022-03-04 17:39:19386 bool partitioned_cookies_exist = false;
387
Ari Chivukula5f21c112022-04-26 19:23:34388 bool cookie_has_not_been_refreshed_in_201_to_300_days = false;
389 bool cookie_has_not_been_refreshed_in_301_to_350_days = false;
390 bool cookie_has_not_been_refreshed_in_351_to_400_days = false;
391
Johann Hofmanne5764d12022-07-13 23:06:28392 bool cookie_has_domain_non_ascii = false;
393
selya19cc0d22024-12-10 20:36:07394 int cookies_exempted_by_top_level_storage_access = 0;
395
Chris Fredrickson6639c0a42025-03-27 21:50:28396 const bool cross_origin_same_site_with_storage_access_eligible =
397 IsCrossOriginSameSiteNetworkAccessWithStorageAccessEligible(
398 cookie_details);
399 bool cross_origin_same_site_cookie_via_storage_access_api = false;
400
cfredric76b2d222021-01-27 20:12:04401 for (const network::mojom::CookieOrLineWithAccessResultPtr& cookie :
Alexander Timin1cc31f42020-05-12 16:26:01402 cookie_details->cookie_list) {
Johann Hofmann975c0b42022-08-02 21:05:51403 const net::CookieInclusionStatus& status = cookie->access_result.status;
404 if (ShouldReportDevToolsIssueForStatus(status)) {
Shuran Huang7a6757c22024-04-17 15:17:39405 std::optional<std::string> devtools_issue_id;
406 if (status.HasExclusionReason(
Chris Fredrickson0a9673e2025-01-21 16:45:14407 net::CookieInclusionStatus::ExclusionReason::
408 EXCLUDE_THIRD_PARTY_PHASEOUT) ||
Chris Fredrickson66f167f2025-01-21 18:18:20409 status.HasWarningReason(net::CookieInclusionStatus::WarningReason::
410 WARN_THIRD_PARTY_PHASEOUT)) {
Shuran Huang7a6757c22024-04-17 15:17:39411 devtools_issue_id = base::UnguessableToken::Create().ToString();
412 }
Juba Borgohainc93969e2022-02-25 21:56:12413 devtools_instrumentation::ReportCookieIssue(
Simon Zünd657178e2021-05-27 06:19:55414 root_frame_host, cookie, cookie_details->url,
415 cookie_details->site_for_cookies,
416 cookie_details->type == CookieAccessDetails::Type::kRead
Juba Borgohainc93969e2022-02-25 21:56:12417 ? blink::mojom::CookieOperation::kReadCookie
418 : blink::mojom::CookieOperation::kSetCookie,
Shuran Huang7a6757c22024-04-17 15:17:39419 cookie_details->devtools_request_id, devtools_issue_id);
Shuran Huang8fa11c72023-12-04 16:53:44420 }
421
cfredric76b2d222021-01-27 20:12:04422 if (cookie->access_result.status.ShouldWarn()) {
Lily Chen9de4065b2020-06-24 20:18:47423 samesite_treated_as_lax_cookies =
424 samesite_treated_as_lax_cookies ||
cfredrica5fb0982021-01-09 00:18:01425 status.HasWarningReason(
Chris Fredrickson66f167f2025-01-21 18:18:20426 net::CookieInclusionStatus::WarningReason::
Lily Chen9de4065b2020-06-24 20:18:47427 WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT) ||
cfredrica5fb0982021-01-09 00:18:01428 status.HasWarningReason(
Chris Fredrickson66f167f2025-01-21 18:18:20429 net::CookieInclusionStatus::WarningReason::
Lily Chen9de4065b2020-06-24 20:18:47430 WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE);
Alexander Timin1cc31f42020-05-12 16:26:01431
Lily Chen9de4065b2020-06-24 20:18:47432 samesite_none_insecure_cookies =
433 samesite_none_insecure_cookies ||
Chris Fredrickson66f167f2025-01-21 18:18:20434 status.HasWarningReason(net::CookieInclusionStatus::WarningReason::
435 WARN_SAMESITE_NONE_INSECURE);
Lily Chen9de4065b2020-06-24 20:18:47436
Lily Chenc4423c02021-03-11 16:02:02437 lax_allow_unsafe_cookies =
438 lax_allow_unsafe_cookies ||
439 status.HasWarningReason(
Chris Fredrickson66f167f2025-01-21 18:18:20440 net::CookieInclusionStatus::WarningReason::
Lily Chenc4423c02021-03-11 16:02:02441 WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE);
442
Lily Chen2db3a422021-07-20 18:02:25443 samesite_cookie_inclusion_changed_by_cross_site_redirect =
444 samesite_cookie_inclusion_changed_by_cross_site_redirect ||
445 status.HasWarningReason(
Chris Fredrickson66f167f2025-01-21 18:18:20446 net::CookieInclusionStatus::WarningReason::
Lily Chen2db3a422021-07-20 18:02:25447 WARN_CROSS_SITE_REDIRECT_DOWNGRADE_CHANGES_INCLUSION);
Alexander Timin1cc31f42020-05-12 16:26:01448 }
Alexander Timin1cc31f42020-05-12 16:26:01449
Johann Hofmann975c0b42022-08-02 21:05:51450 cookie_has_domain_non_ascii =
451 cookie_has_domain_non_ascii ||
452 status.HasWarningReason(
Chris Fredrickson66f167f2025-01-21 18:18:20453 net::CookieInclusionStatus::WarningReason::WARN_DOMAIN_NON_ASCII) ||
Chris Fredrickson0a9673e2025-01-21 16:45:14454 status.HasExclusionReason(net::CookieInclusionStatus::ExclusionReason::
455 EXCLUDE_DOMAIN_NON_ASCII);
Johann Hofmann975c0b42022-08-02 21:05:51456
Dylan Cutler8d5f8912022-03-04 17:39:19457 partitioned_cookies_exist =
458 partitioned_cookies_exist ||
459 (cookie->cookie_or_line->is_cookie() &&
Dylan Cutler051411b42022-07-12 22:20:07460 cookie->cookie_or_line->get_cookie().IsPartitioned() &&
461 // Ignore nonced partition keys since this metric is meant to track
462 // usage of the Partitioned attribute.
463 !cookie->cookie_or_line->get_cookie().PartitionKey()->nonce());
Dylan Cutler8d5f8912022-03-04 17:39:19464
selya27d093e2023-08-02 22:20:00465
selya778265bc2023-10-23 14:37:55466 if (partitioned_cookies_exist) {
selya7d96d6182024-04-22 11:35:51467 RecordPartitionedCookiesUKMs(rfh, cookie->cookie_or_line->get_cookie());
selya778265bc2023-10-23 14:37:55468 }
469
selya19cc0d22024-12-10 20:36:07470 if (cookie->access_result.status.exemption_reason() ==
471 net::CookieInclusionStatus::ExemptionReason::kTopLevelStorageAccess) {
472 cookies_exempted_by_top_level_storage_access++;
473 }
474
Ayu Ishii2e3998902020-07-14 18:22:30475 breaking_context_downgrade =
476 breaking_context_downgrade ||
sbingler870b63f2023-04-25 16:47:58477 cookie->access_result.status.HasSchemefulDowngradeWarning();
Alexander Timin1cc31f42020-05-12 16:26:01478
sbingler870b63f2023-04-25 16:47:58479 if (cookie->access_result.status.HasSchemefulDowngradeWarning()) {
480 // Unlike with UMA, do not record cookies that have no schemeful downgrade
481 // warning.
482 RecordSchemefulContextDowngradeUKM(rfh, cookie_details->type,
483 cookie->access_result.status,
484 cookie_details->url);
485 }
486
487 if (status.HasWarningReason(
Chris Fredrickson66f167f2025-01-21 18:18:20488 net::CookieInclusionStatus::WarningReason::
sbingler870b63f2023-04-25 16:47:58489 WARN_CROSS_SITE_REDIRECT_DOWNGRADE_CHANGES_INCLUSION) &&
490 cookie->cookie_or_line->is_cookie()) {
491 RecordRedirectContextDowngradeUKM(rfh, cookie_details->type,
492 cookie->cookie_or_line->get_cookie(),
493 cookie_details->url);
Alexander Timin1cc31f42020-05-12 16:26:01494 }
Ari Chivukula5f21c112022-04-26 19:23:34495
sbingler8e26e212023-09-27 23:23:27496 if (cookie->cookie_or_line->is_cookie()) {
497 PotentiallyRecordNonAsciiCookieNameValue(
498 rfh, cookie_details->type,
499 cookie->cookie_or_line->get_cookie().Name(),
500 cookie->cookie_or_line->get_cookie().Value());
501 }
502
amarjotgilld43eb5d12024-11-11 17:53:36503 PotentiallyRecordCookieOriginMismatch(rfh, cookie_details->type, status);
504
Ari Chivukula5f21c112022-04-26 19:23:34505 // In order to anticipate the potential effects of the expiry limit in
506 // rfc6265bis, we need to check how long it's been since the cookie was
507 // refreshed (if LastUpdateDate is populated). These three buckets were
508 // picked so we could engage sites with some granularity around urgency.
509 // We ignore the space under 200 days as these cookies are not at risk
510 // of expiring and we ignore the space over 400 days as these cookies
511 // have already expired. Metrics will take 200 days from M103 to populate.
512 base::Time last_update_date =
513 cookie->cookie_or_line->is_cookie()
514 ? cookie->cookie_or_line->get_cookie().LastUpdateDate()
515 : base::Time();
516 if (!last_update_date.is_null()) {
517 int days_since_refresh = (base::Time::Now() - last_update_date).InDays();
518 cookie_has_not_been_refreshed_in_201_to_300_days |=
519 days_since_refresh > 200 && days_since_refresh <= 300;
520 cookie_has_not_been_refreshed_in_301_to_350_days |=
521 days_since_refresh > 300 && days_since_refresh <= 350;
522 cookie_has_not_been_refreshed_in_351_to_400_days |=
523 days_since_refresh > 350 && days_since_refresh <= 400;
524 }
Chris Fredrickson6639c0a42025-03-27 21:50:28525
526 cross_origin_same_site_cookie_via_storage_access_api |=
527 cross_origin_same_site_with_storage_access_eligible &&
528 cookie->access_result.status.IsInclude() &&
529 cookie->access_result.status.exemption_reason() ==
530 net::CookieInclusionStatus::ExemptionReason::kStorageAccess;
Alexander Timin1cc31f42020-05-12 16:26:01531 }
532
Alexander Timin1cc31f42020-05-12 16:26:01533 if (samesite_treated_as_lax_cookies) {
534 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
535 rfh, blink::mojom::WebFeature::kCookieNoSameSite);
536 }
537
538 if (samesite_none_insecure_cookies) {
539 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
540 rfh, blink::mojom::WebFeature::kCookieInsecureAndSameSiteNone);
541 }
542
543 if (breaking_context_downgrade) {
544 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
545 rfh, blink::mojom::WebFeature::kSchemefulSameSiteContextDowngrade);
546 }
cfredrica5fb0982021-01-09 00:18:01547
Lily Chenc4423c02021-03-11 16:02:02548 if (lax_allow_unsafe_cookies) {
549 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
550 rfh, blink::mojom::WebFeature::kLaxAllowingUnsafeCookies);
551 }
552
Lily Chen2db3a422021-07-20 18:02:25553 if (samesite_cookie_inclusion_changed_by_cross_site_redirect) {
554 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
555 rfh, blink::mojom::WebFeature::
556 kSameSiteCookieInclusionChangedByCrossSiteRedirect);
557 }
Dylan Cutler8d5f8912022-03-04 17:39:19558
559 if (partitioned_cookies_exist) {
560 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
561 rfh, blink::mojom::WebFeature::kPartitionedCookies);
562 }
Ari Chivukula5f21c112022-04-26 19:23:34563
564 if (cookie_has_not_been_refreshed_in_201_to_300_days) {
565 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
566 rfh,
567 blink::mojom::WebFeature::kCookieHasNotBeenRefreshedIn201To300Days);
568 }
569
570 if (cookie_has_not_been_refreshed_in_301_to_350_days) {
571 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
572 rfh,
573 blink::mojom::WebFeature::kCookieHasNotBeenRefreshedIn301To350Days);
574 }
575
576 if (cookie_has_not_been_refreshed_in_351_to_400_days) {
577 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
578 rfh,
579 blink::mojom::WebFeature::kCookieHasNotBeenRefreshedIn351To400Days);
580 }
Johann Hofmanne5764d12022-07-13 23:06:28581
582 if (cookie_has_domain_non_ascii) {
583 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
584 rfh, blink::mojom::WebFeature::kCookieDomainNonASCII);
585 }
selya19cc0d22024-12-10 20:36:07586
587 if (cookies_exempted_by_top_level_storage_access) {
588 RecordCookiesExemptedByTopLevelStorage(
589 rfh->GetPageUkmSourceId(),
590 cookies_exempted_by_top_level_storage_access);
591 }
Chris Fredrickson6639c0a42025-03-27 21:50:28592
593 if (cross_origin_same_site_cookie_via_storage_access_api) {
594 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
595 rfh, blink::mojom::WebFeature::
596 kCrossOriginSameSiteCookieAccessViaStorageAccessAPI);
597 }
Alexander Timin1cc31f42020-05-12 16:26:01598}
599
Alexander Timin1cc31f42020-05-12 16:26:01600} // namespace content