Alexander Timin | 1cc31f4 | 2020-05-12 16:26:01 | [diff] [blame^] | 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/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 | |
| 17 | namespace content { |
| 18 | |
| 19 | namespace { |
| 20 | |
| 21 | void 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 | |
| 43 | void 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 | |
| 71 | void 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 |