blob: c854504519b16e586f20b2411ce83883a0be07d7 [file] [log] [blame]
Alexander Timin1cc31f42020-05-12 16:26:011// 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
5#include "content/browser/frame_host/cookie_utils.h"
6
7#include "content/browser/devtools/devtools_instrumentation.h"
8#include "content/browser/frame_host/frame_tree_node.h"
9#include "content/browser/frame_host/render_frame_host_impl.h"
10#include "content/public/browser/browser_context.h"
11#include "content/public/browser/cookie_access_details.h"
12#include "content/public/common/content_client.h"
13#include "content/public/common/content_features.h"
14#include "net/cookies/cookie_util.h"
15#include "services/metrics/public/cpp/ukm_builders.h"
16
17namespace content {
18
19namespace {
20
21void RecordContextDowngradeUKM(
22 RenderFrameHost* rfh,
23 CookieAccessDetails::Type access_type,
24 const net::CanonicalCookie::CookieInclusionStatus& status,
25 const GURL& url) {
26 DCHECK(rfh);
27 ukm::SourceId source_id = rfh->GetPageUkmSourceId();
28
29 if (access_type == CookieAccessDetails::Type::kRead) {
30 ukm::builders::SchemefulSameSiteContextDowngrade(source_id)
31 .SetRequestPerCookie(status.GetBreakingDowngradeMetricsEnumValue(url))
32 .Record(ukm::UkmRecorder::Get());
33 } else {
34 DCHECK(access_type == CookieAccessDetails::Type::kChange);
35 ukm::builders::SchemefulSameSiteContextDowngrade(source_id)
36 .SetResponsePerCookie(status.GetBreakingDowngradeMetricsEnumValue(url))
37 .Record(ukm::UkmRecorder::Get());
38 }
39}
40
41} // namespace
42
43void SplitCookiesIntoAllowedAndBlocked(
44 const network::mojom::CookieAccessDetailsPtr& cookie_details,
45 CookieAccessDetails* allowed,
46 CookieAccessDetails* blocked) {
47 *allowed =
48 CookieAccessDetails({cookie_details->type,
49 cookie_details->url,
50 cookie_details->site_for_cookies.RepresentativeUrl(),
51 {},
52 /* blocked_by_policy=*/false});
53 *blocked =
54 CookieAccessDetails({cookie_details->type,
55 cookie_details->url,
56 cookie_details->site_for_cookies.RepresentativeUrl(),
57 {},
58 /* blocked_by_policy=*/true});
59
60 for (auto& cookie_and_status : cookie_details->cookie_list) {
61 if (cookie_and_status.status.HasExclusionReason(
62 net::CanonicalCookie::CookieInclusionStatus::
63 EXCLUDE_USER_PREFERENCES)) {
64 blocked->cookie_list.push_back(std::move(cookie_and_status.cookie));
65 } else if (cookie_and_status.status.IsInclude()) {
66 allowed->cookie_list.push_back(std::move(cookie_and_status.cookie));
67 }
68 }
69}
70
71void EmitSameSiteCookiesDeprecationWarning(
72 RenderFrameHostImpl* rfh,
73 const network::mojom::CookieAccessDetailsPtr& cookie_details) {
74 RenderFrameHostImpl* root_frame_host = rfh->GetMainFrame();
75
76 if (!root_frame_host->IsCurrent())
77 return;
78
79 bool samesite_treated_as_lax_cookies = false;
80 bool samesite_none_insecure_cookies = false;
81
82 bool messages_disabled_by_cmdline =
83 base::FeatureList::GetInstance()->IsFeatureOverriddenFromCommandLine(
84 features::kCookieDeprecationMessages.name,
85 base::FeatureList::OVERRIDE_DISABLE_FEATURE);
86 bool emit_messages =
87 !messages_disabled_by_cmdline &&
88 (net::cookie_util::IsSameSiteByDefaultCookiesEnabled() ||
89 net::cookie_util::IsCookiesWithoutSameSiteMustBeSecureEnabled() ||
90 base::FeatureList::IsEnabled(features::kCookieDeprecationMessages));
91
92 bool breaking_context_downgrade = false;
93
94 for (const net::CookieWithStatus& excluded_cookie :
95 cookie_details->cookie_list) {
96 std::string cookie_url =
97 net::cookie_util::CookieOriginToURL(excluded_cookie.cookie.Domain(),
98 excluded_cookie.cookie.IsSecure())
99 .possibly_invalid_spec();
100
101 if (excluded_cookie.status.ShouldWarn()) {
102 if (excluded_cookie.status.HasWarningReason(
103 net::CanonicalCookie::CookieInclusionStatus::
104 WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT)) {
105 samesite_treated_as_lax_cookies = true;
106 }
107
108 if (excluded_cookie.status.HasWarningReason(
109 net::CanonicalCookie::CookieInclusionStatus::
110 WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE)) {
111 samesite_treated_as_lax_cookies = true;
112 }
113
114 if (excluded_cookie.status.HasWarningReason(
115 net::CanonicalCookie::CookieInclusionStatus::
116 WARN_SAMESITE_NONE_INSECURE)) {
117 samesite_none_insecure_cookies = true;
118 }
119 devtools_instrumentation::ReportSameSiteCookieIssue(
120 root_frame_host, excluded_cookie, cookie_details->url,
121 cookie_details->site_for_cookies,
122 cookie_details->type == CookieAccessDetails::Type::kRead
123 ? blink::mojom::SameSiteCookieOperation::ReadCookie
124 : blink::mojom::SameSiteCookieOperation::SetCookie,
125 cookie_details->devtools_request_id);
126 }
127 if (emit_messages) {
128 root_frame_host->AddSameSiteCookieDeprecationMessage(
129 cookie_url, excluded_cookie.status,
130 net::cookie_util::IsSameSiteByDefaultCookiesEnabled(),
131 net::cookie_util::IsCookiesWithoutSameSiteMustBeSecureEnabled());
132 }
133
134 breaking_context_downgrade = breaking_context_downgrade ||
135 excluded_cookie.status.HasDowngradeWarning();
136
137 if (excluded_cookie.status.ShouldRecordDowngradeMetrics()) {
138 RecordContextDowngradeUKM(rfh, cookie_details->type,
139 excluded_cookie.status, cookie_details->url);
140 }
141 }
142
143 // TODO(crbug.com/990439): Do we need separate UseCounter metrics for
144 // Lax-allow-unsafe? We already have histograms in CanonicalCookie.
145 if (samesite_treated_as_lax_cookies) {
146 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
147 rfh, blink::mojom::WebFeature::kCookieNoSameSite);
148 }
149
150 if (samesite_none_insecure_cookies) {
151 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
152 rfh, blink::mojom::WebFeature::kCookieInsecureAndSameSiteNone);
153 }
154
155 if (breaking_context_downgrade) {
156 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
157 rfh, blink::mojom::WebFeature::kSchemefulSameSiteContextDowngrade);
158 }
159}
160
161} // namespace content