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