1 // 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/renderer_host/cookie_utils.h"
6
7 #include "content/browser/devtools/devtools_instrumentation.h"
8 #include "content/browser/renderer_host/frame_tree_node.h"
9 #include "content/browser/renderer_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 "net/cookies/cookie_inclusion_status.h"
14 #include "services/metrics/public/cpp/ukm_builders.h"
15
16 namespace content {
17
18 namespace {
19
RecordContextDowngradeUKM(RenderFrameHost * rfh,CookieAccessDetails::Type access_type,const net::CookieInclusionStatus & status,const GURL & url)20 void RecordContextDowngradeUKM(RenderFrameHost* rfh,
21 CookieAccessDetails::Type access_type,
22 const net::CookieInclusionStatus& status,
23 const GURL& url) {
24 DCHECK(rfh);
25 ukm::SourceId source_id = rfh->GetPageUkmSourceId();
26
27 if (access_type == CookieAccessDetails::Type::kRead) {
28 ukm::builders::SchemefulSameSiteContextDowngrade(source_id)
29 .SetRequestPerCookie(status.GetBreakingDowngradeMetricsEnumValue(url))
30 .Record(ukm::UkmRecorder::Get());
31 } else {
32 DCHECK(access_type == CookieAccessDetails::Type::kChange);
33 ukm::builders::SchemefulSameSiteContextDowngrade(source_id)
34 .SetResponsePerCookie(status.GetBreakingDowngradeMetricsEnumValue(url))
35 .Record(ukm::UkmRecorder::Get());
36 }
37 }
38
39 } // namespace
40
SplitCookiesIntoAllowedAndBlocked(const network::mojom::CookieAccessDetailsPtr & cookie_details,CookieAccessDetails * allowed,CookieAccessDetails * blocked)41 void SplitCookiesIntoAllowedAndBlocked(
42 const network::mojom::CookieAccessDetailsPtr& cookie_details,
43 CookieAccessDetails* allowed,
44 CookieAccessDetails* blocked) {
45 *allowed =
46 CookieAccessDetails({cookie_details->type,
47 cookie_details->url,
48 cookie_details->site_for_cookies.RepresentativeUrl(),
49 {},
50 /* blocked_by_policy=*/false});
51 *blocked =
52 CookieAccessDetails({cookie_details->type,
53 cookie_details->url,
54 cookie_details->site_for_cookies.RepresentativeUrl(),
55 {},
56 /* blocked_by_policy=*/true});
57
58 for (auto& cookie_and_access_result : cookie_details->cookie_list) {
59 if (cookie_and_access_result.access_result.status.HasOnlyExclusionReason(
60 net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES)) {
61 blocked->cookie_list.push_back(
62 std::move(cookie_and_access_result.cookie));
63 } else if (cookie_and_access_result.access_result.status.IsInclude()) {
64 allowed->cookie_list.push_back(
65 std::move(cookie_and_access_result.cookie));
66 }
67 }
68 }
69
EmitSameSiteCookiesDeprecationWarning(RenderFrameHostImpl * rfh,const network::mojom::CookieAccessDetailsPtr & cookie_details)70 void EmitSameSiteCookiesDeprecationWarning(
71 RenderFrameHostImpl* rfh,
72 const network::mojom::CookieAccessDetailsPtr& cookie_details) {
73 RenderFrameHostImpl* root_frame_host = rfh->GetMainFrame();
74
75 if (!root_frame_host->IsCurrent())
76 return;
77
78 bool samesite_treated_as_lax_cookies = false;
79 bool samesite_none_insecure_cookies = false;
80 bool breaking_context_downgrade = false;
81
82 for (const net::CookieWithAccessResult& excluded_cookie :
83 cookie_details->cookie_list) {
84 if (excluded_cookie.access_result.status.ShouldWarn()) {
85 samesite_treated_as_lax_cookies =
86 samesite_treated_as_lax_cookies ||
87 excluded_cookie.access_result.status.HasWarningReason(
88 net::CookieInclusionStatus::
89 WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT) ||
90 excluded_cookie.access_result.status.HasWarningReason(
91 net::CookieInclusionStatus::
92 WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE);
93
94 samesite_none_insecure_cookies =
95 samesite_none_insecure_cookies ||
96 excluded_cookie.access_result.status.HasWarningReason(
97 net::CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE);
98
99 devtools_instrumentation::ReportSameSiteCookieIssue(
100 root_frame_host, excluded_cookie, cookie_details->url,
101 cookie_details->site_for_cookies,
102 cookie_details->type == CookieAccessDetails::Type::kRead
103 ? blink::mojom::SameSiteCookieOperation::kReadCookie
104 : blink::mojom::SameSiteCookieOperation::kSetCookie,
105 cookie_details->devtools_request_id);
106 }
107
108 breaking_context_downgrade =
109 breaking_context_downgrade ||
110 excluded_cookie.access_result.status.HasDowngradeWarning();
111
112 if (excluded_cookie.access_result.status.HasDowngradeWarning()) {
113 // Unlike with UMA, do not record cookies that have no downgrade warning.
114 RecordContextDowngradeUKM(rfh, cookie_details->type,
115 excluded_cookie.access_result.status,
116 cookie_details->url);
117 }
118 }
119
120 if (samesite_treated_as_lax_cookies) {
121 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
122 rfh, blink::mojom::WebFeature::kCookieNoSameSite);
123 }
124
125 if (samesite_none_insecure_cookies) {
126 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
127 rfh, blink::mojom::WebFeature::kCookieInsecureAndSameSiteNone);
128 }
129
130 if (breaking_context_downgrade) {
131 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
132 rfh, blink::mojom::WebFeature::kSchemefulSameSiteContextDowngrade);
133 }
134 }
135
136 } // namespace content
137