From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Zoraver Kang Date: Sun, 30 Jul 2023 14:08:17 -0400 Subject: [PATCH] make cross-origin referrer behavior configurable This is implemented in a similar manner to the enable_referrers preference. The chrome for the cross-origin referrer policy preference is based on 0089-Implement-UI-for-WebRTC-toggle.patch. --- chrome/android/chrome_ext_java_resources.gni | 2 + chrome/android/chrome_ext_java_sources.gni | 3 + ...ross_origin_referrer_policy_preference.xml | 45 ++++++++++ ...oss_origin_referrer_policy_preferences.xml | 9 ++ .../java/res/xml/privacy_preferences_ext.xml | 4 + .../privacy/settings/PrivacySettingsExt.java | 15 ++++ .../CrossOriginReferrerPolicyPreference.java | 89 +++++++++++++++++++ .../CrossOriginReferrerPolicySettings.java | 54 +++++++++++ .../CrossOriginReferrerPolicyUtils.java | 45 ++++++++++ .../net/profile_network_context_service.cc | 19 ++++ .../net/profile_network_context_service.h | 2 + chrome/browser/renderer_preferences_util.cc | 3 + .../strings/android_chrome_ext_strings.grdp | 13 +++ chrome/browser/ui/prefs/pref_watcher.cc | 2 + chrome/common/pref_names.h | 4 + .../renderer_host/navigation_request.cc | 23 +++++ content/renderer/render_frame_impl.cc | 25 ++++++ services/network/network_context.cc | 10 +++ services/network/network_context.h | 3 + .../network_service_network_delegate.cc | 29 ++++++ .../network_service_network_delegate.h | 8 ++ .../public/mojom/network_context.mojom | 14 +++ .../renderer_preferences_mojom_traits.cc | 1 + .../renderer_preferences.h | 4 + .../renderer_preferences_mojom_traits.h | 5 ++ .../public/mojom/renderer_preferences.mojom | 5 ++ .../web_service_worker_fetch_context_impl.cc | 27 ++++++ ...ted_or_shared_worker_fetch_context_impl.cc | 27 ++++++ 28 files changed, 490 insertions(+) create mode 100644 chrome/android/java/res/layout/cross_origin_referrer_policy_preference.xml create mode 100644 chrome/android/java/res/xml/cross_origin_referrer_policy_preferences.xml create mode 100644 chrome/android/java/src/org/chromium/chrome/browser/referrer/settings/CrossOriginReferrerPolicyPreference.java create mode 100644 chrome/android/java/src/org/chromium/chrome/browser/referrer/settings/CrossOriginReferrerPolicySettings.java create mode 100644 chrome/android/java/src/org/chromium/chrome/browser/referrer/settings/CrossOriginReferrerPolicyUtils.java diff --git a/chrome/android/chrome_ext_java_resources.gni b/chrome/android/chrome_ext_java_resources.gni index 4b55afd038612..06942accf63b8 100644 --- a/chrome/android/chrome_ext_java_resources.gni +++ b/chrome/android/chrome_ext_java_resources.gni @@ -6,4 +6,6 @@ chrome_ext_java_resources = [ "java/res/xml/privacy_preferences_ext.xml", "java/res/layout/webrtc_policy_preference.xml", "java/res/xml/webrtc_policy_preferences.xml", + "java/res/layout/cross_origin_referrer_policy_preference.xml", + "java/res/xml/cross_origin_referrer_policy_preferences.xml", ] diff --git a/chrome/android/chrome_ext_java_sources.gni b/chrome/android/chrome_ext_java_sources.gni index 77963fdccafca..27518fd27d8b2 100644 --- a/chrome/android/chrome_ext_java_sources.gni +++ b/chrome/android/chrome_ext_java_sources.gni @@ -9,4 +9,7 @@ chrome_ext_java_sources = [ "java/src/org/chromium/chrome/browser/webrtc/settings/WebRtcPolicyPreference.java", "java/src/org/chromium/chrome/browser/webrtc/settings/WebRtcPolicySettings.java", "java/src/org/chromium/chrome/browser/webrtc/settings/WebRtcPolicyUtils.java", + "java/src/org/chromium/chrome/browser/referrer/settings/CrossOriginReferrerPolicyPreference.java", + "java/src/org/chromium/chrome/browser/referrer/settings/CrossOriginReferrerPolicySettings.java", + "java/src/org/chromium/chrome/browser/referrer/settings/CrossOriginReferrerPolicyUtils.java", ] diff --git a/chrome/android/java/res/layout/cross_origin_referrer_policy_preference.xml b/chrome/android/java/res/layout/cross_origin_referrer_policy_preference.xml new file mode 100644 index 0000000000000..26b4e20337b93 --- /dev/null +++ b/chrome/android/java/res/layout/cross_origin_referrer_policy_preference.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + diff --git a/chrome/android/java/res/xml/cross_origin_referrer_policy_preferences.xml b/chrome/android/java/res/xml/cross_origin_referrer_policy_preferences.xml new file mode 100644 index 0000000000000..b59eb277d52c2 --- /dev/null +++ b/chrome/android/java/res/xml/cross_origin_referrer_policy_preferences.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/chrome/android/java/res/xml/privacy_preferences_ext.xml b/chrome/android/java/res/xml/privacy_preferences_ext.xml index 6e955e33c0109..356e4204e1cd2 100644 --- a/chrome/android/java/res/xml/privacy_preferences_ext.xml +++ b/chrome/android/java/res/xml/privacy_preferences_ext.xml @@ -24,5 +24,9 @@ that can be found in the LICENSE file. android:key="webrtc_policy" android:title="@string/webrtc_policy_title" android:fragment="org.chromium.chrome.browser.webrtc.settings.WebRtcPolicySettings"/> + diff --git a/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettingsExt.java b/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettingsExt.java index e356a9feb6f77..0fff8771be060 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettingsExt.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettingsExt.java @@ -15,6 +15,7 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.preferences.Pref; import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.referrer.settings.CrossOriginReferrerPolicySettings; import org.chromium.chrome.browser.settings.ChromeManagedPreferenceDelegate; import org.chromium.chrome.browser.settings.SettingsExtUtils; import org.chromium.chrome.browser.webrtc.settings.WebRtcPolicySettings; @@ -31,6 +32,7 @@ final class PrivacySettingsExt { private static final String PREF_OPEN_LINKS_IN_INCOGNITO = SharedPrefsExt.OPEN_LINKS_IN_INCOGNITO.getKey(); private static final String PREF_WEBRTC_POLICY = "webrtc_policy"; + private static final String PREF_CROSS_ORIGIN_REFERRER_POLICY = "cross_origin_referrer_policy"; private static final Preference.OnPreferenceChangeListener getListener(@NonNull Profile profile) { return (pref, val) -> { @@ -106,6 +108,12 @@ final class PrivacySettingsExt { if (webRtcPolicyPref != null) { webRtcPolicyPref.setOrder(PRIVACY_PREFERENCES_ORDER); } + + final Preference crossOriginReferrerPolicyPref = + prefFragment.findPreference(PREF_CROSS_ORIGIN_REFERRER_POLICY); + if (crossOriginReferrerPolicyPref != null) { + crossOriginReferrerPolicyPref.setOrder(PRIVACY_PREFERENCES_ORDER); + } } static void updatePreferences(@NonNull PreferenceFragmentCompat prefFragment, @NonNull Profile profile) { @@ -132,5 +140,12 @@ final class PrivacySettingsExt { Preference webRtcPolicyPref = prefFragment.findPreference(PREF_WEBRTC_POLICY); SettingsExtUtils.safelyUpdatePreference(/* preference */ webRtcPolicyPref, /* newSummary */ WebRtcPolicySettings.getWebRtcPolicySummaryString(prefFragment.getContext())); + + final Preference crossOriginReferrerPolicyPref = + prefFragment.findPreference(PREF_CROSS_ORIGIN_REFERRER_POLICY); + SettingsExtUtils.safelyUpdatePreference(/* preference */ crossOriginReferrerPolicyPref, + /* newSummary */ CrossOriginReferrerPolicySettings + .getCrossOriginReferrerPolicySummaryString( + prefFragment.getContext())); } } diff --git a/chrome/android/java/src/org/chromium/chrome/browser/referrer/settings/CrossOriginReferrerPolicyPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/referrer/settings/CrossOriginReferrerPolicyPreference.java new file mode 100644 index 0000000000000..24feef642b0fa --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/referrer/settings/CrossOriginReferrerPolicyPreference.java @@ -0,0 +1,89 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.chromium.chrome.browser.referrer.settings; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.util.AttributeSet; +import android.widget.RadioGroup; + +import androidx.annotation.IntDef; +import androidx.preference.Preference; +import androidx.preference.PreferenceViewHolder; + +import org.chromium.chrome.R; +import org.chromium.components.browser_ui.widget.RadioButtonWithDescription; +import org.chromium.components.browser_ui.widget.RadioButtonWithDescriptionLayout; + +import java.util.ArrayList; +import java.util.Collections; + +public class CrossOriginReferrerPolicyPreference + extends Preference implements RadioGroup.OnCheckedChangeListener { + @IntDef({CrossOriginReferrerPolicy.DEFAULT, CrossOriginReferrerPolicy.REDUCE, + CrossOriginReferrerPolicy.DISABLE}) + public @interface CrossOriginReferrerPolicy { + int DEFAULT = 0; + int REDUCE = 1; + int DISABLE = 2; + + int NUM_ENTRIES = 3; + } + + private @CrossOriginReferrerPolicy int mSetting; + private RadioButtonWithDescription mSettingRadioButton; + private RadioButtonWithDescriptionLayout mGroup; + private ArrayList mButtons; + + @SuppressLint("WrongConstant") + public CrossOriginReferrerPolicyPreference(Context context, AttributeSet attrs) { + super(context, attrs); + + setLayoutResource(R.layout.cross_origin_referrer_policy_preference); + + mButtons = new ArrayList<>(Collections.nCopies(CrossOriginReferrerPolicy.NUM_ENTRIES, null)); + } + + public void initialize(@CrossOriginReferrerPolicy int policy) { + mSetting = policy; + } + + @Override + public void onBindViewHolder(PreferenceViewHolder holder) { + super.onBindViewHolder(holder); + + mGroup = (RadioButtonWithDescriptionLayout) holder.findViewById(R.id.radio_button_layout); + mGroup.setOnCheckedChangeListener(this); + + mButtons.set(CrossOriginReferrerPolicy.DEFAULT, + (RadioButtonWithDescription) holder.findViewById( + R.id.cross_origin_referrer_policy_default)); + mButtons.set(CrossOriginReferrerPolicy.REDUCE, + (RadioButtonWithDescription) holder.findViewById( + R.id.cross_origin_referrer_policy_reduce)); + mButtons.set(CrossOriginReferrerPolicy.DISABLE, + (RadioButtonWithDescription) holder.findViewById( + R.id.cross_origin_referrer_policy_disable)); + + mSettingRadioButton = mButtons.get(mSetting); + mSettingRadioButton.setChecked(true); + } + + @Override + @SuppressLint("WrongConstant") + public void onCheckedChanged(RadioGroup group, int checkedId) { + for (int i = 0; i < CrossOriginReferrerPolicy.NUM_ENTRIES; i++) { + if (mButtons.get(i).isChecked()) { + mSetting = i; + mSettingRadioButton = mButtons.get(i); + break; + } + } + assert mSetting >= 0 && mSetting < CrossOriginReferrerPolicy.NUM_ENTRIES : "No matching setting found."; + + callChangeListener(mSetting); + } +} diff --git a/chrome/android/java/src/org/chromium/chrome/browser/referrer/settings/CrossOriginReferrerPolicySettings.java b/chrome/android/java/src/org/chromium/chrome/browser/referrer/settings/CrossOriginReferrerPolicySettings.java new file mode 100644 index 0000000000000..b6767fbeb733f --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/referrer/settings/CrossOriginReferrerPolicySettings.java @@ -0,0 +1,54 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.chromium.chrome.browser.referrer.settings; + +import android.content.Context; +import android.os.Build; +import android.os.Bundle; + +import androidx.annotation.Nullable; +import androidx.preference.PreferenceFragmentCompat; + +import org.chromium.chrome.R; +import org.chromium.components.browser_ui.settings.SettingsUtils; +import org.chromium.ui.UiUtils; + +public class CrossOriginReferrerPolicySettings extends PreferenceFragmentCompat { + static final String PREF_CROSS_ORIGIN_REFERRER_POLICY = "cross_origin_referrer_policy"; + + @Override + public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) { + SettingsUtils.addPreferencesFromResource(this, + R.xml.cross_origin_referrer_policy_preferences); + getActivity().setTitle(R.string.cross_origin_referrer_policy_title); + + CrossOriginReferrerPolicyPreference crossOriginReferrerPolicyPreference = + (CrossOriginReferrerPolicyPreference) findPreference( + PREF_CROSS_ORIGIN_REFERRER_POLICY); + crossOriginReferrerPolicyPreference.initialize(CrossOriginReferrerPolicyUtils.getPolicy()); + + crossOriginReferrerPolicyPreference.setOnPreferenceChangeListener((preference, newValue) -> { + CrossOriginReferrerPolicyUtils.setPolicy((int) newValue); + return true; + }); + } + + public static String getCrossOriginReferrerPolicySummaryString(Context context) { + return CrossOriginReferrerPolicyUtils.getSummary(context); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O_MR1) { + UiUtils.setNavigationBarIconColor(getActivity().getWindow().getDecorView(), + getResources().getBoolean(R.bool.window_light_navigation_bar)); + } + + setDivider(null); + } +} diff --git a/chrome/android/java/src/org/chromium/chrome/browser/referrer/settings/CrossOriginReferrerPolicyUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/referrer/settings/CrossOriginReferrerPolicyUtils.java new file mode 100644 index 0000000000000..08edd73498493 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/referrer/settings/CrossOriginReferrerPolicyUtils.java @@ -0,0 +1,45 @@ +// Copyright 2023 GrapheneOS +// Use of this source code is governed by a GPLv2 only-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.referrer.settings; + +import android.content.Context; + +import org.chromium.chrome.R; +import org.chromium.chrome.browser.preferences.Pref; +import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.referrer.settings.CrossOriginReferrerPolicyPreference.CrossOriginReferrerPolicy; +import org.chromium.components.user_prefs.UserPrefs; + +/** + * Utility class for fetching and setting native pref values for cross-origin referrer policy + * and retrieving their corresponding descriptions. + */ +class CrossOriginReferrerPolicyUtils { + static String getSummary(Context context) { + switch (getPolicy()) { + case CrossOriginReferrerPolicy.DEFAULT: + return context.getString(R.string.cross_origin_referrer_policy_default); + case CrossOriginReferrerPolicy.REDUCE: + return context.getString(R.string.cross_origin_referrer_policy_reduce); + case CrossOriginReferrerPolicy.DISABLE: + return context.getString(R.string.cross_origin_referrer_policy_disable); + default: + assert false; + return ""; + } + } + + static @CrossOriginReferrerPolicy int getPolicy() { + return UserPrefs.get(Profile.getLastUsedRegularProfile()) + .getInteger(Pref.CROSS_ORIGIN_REFERRER_POLICY); + } + + static void setPolicy(@CrossOriginReferrerPolicy int policy) { + UserPrefs.get(Profile.getLastUsedRegularProfile()) + .setInteger(Pref.CROSS_ORIGIN_REFERRER_POLICY, policy); + } + + private CrossOriginReferrerPolicyUtils() {} +} diff --git a/chrome/browser/net/profile_network_context_service.cc b/chrome/browser/net/profile_network_context_service.cc index a3c64d526dd54..a57bcf955df98 100644 --- a/chrome/browser/net/profile_network_context_service.cc +++ b/chrome/browser/net/profile_network_context_service.cc @@ -74,6 +74,7 @@ #include "services/network/public/cpp/cors/origin_access_list.h" #include "services/network/public/cpp/features.h" #include "services/network/public/mojom/first_party_sets_access_delegate.mojom.h" +#include "services/network/public/mojom/network_context.mojom-shared.h" #include "services/network/public/mojom/network_context.mojom.h" #include "services/network/public/mojom/network_service.mojom.h" #include "third_party/blink/public/common/features.h" @@ -318,6 +319,11 @@ ProfileNetworkContextService::ProfileNetworkContextService(Profile* profile) prefs::kEnableReferrers, profile_prefs, base::BindRepeating(&ProfileNetworkContextService::UpdateReferrersEnabled, base::Unretained(this))); + cross_origin_referrer_policy_.Init( + prefs::kCrossOriginReferrerPolicy, profile_prefs, + base::BindRepeating( + &ProfileNetworkContextService::UpdateCrossOriginReferrerPolicy, + base::Unretained(this))); cookie_settings_ = CookieSettingsFactory::GetForProfile(profile); cookie_settings_observation_.Observe(cookie_settings_.get()); privacy_sandbox_settings_observer_.Observe( @@ -416,6 +422,8 @@ void ProfileNetworkContextService::RegisterProfilePrefs( registry->RegisterBooleanPref(prefs::kGloballyScopeHTTPAuthCacheEnabled, false); registry->RegisterListPref(prefs::kHSTSPolicyBypassList); + registry->RegisterIntegerPref(prefs::kCrossOriginReferrerPolicy, + static_cast(network::mojom::CrossOriginReferrerPolicy::kDefault)); } // static @@ -520,6 +528,17 @@ void ProfileNetworkContextService::UpdateReferrersEnabled() { enable_referrers_.GetValue())); } +void ProfileNetworkContextService::UpdateCrossOriginReferrerPolicy() { + profile_->ForEachLoadedStoragePartition(base::BindRepeating( + [](int cross_origin_referrer_policy, + content::StoragePartition* storage_partition) { + storage_partition->GetNetworkContext()->SetCrossOriginReferrerPolicy( + static_cast( + cross_origin_referrer_policy)); + }, + cross_origin_referrer_policy_.GetValue())); +} + network::mojom::CTPolicyPtr ProfileNetworkContextService::GetCTPolicy() { auto* prefs = profile_->GetPrefs(); const base::Value::List& ct_excluded = diff --git a/chrome/browser/net/profile_network_context_service.h b/chrome/browser/net/profile_network_context_service.h index 3a05ed05828c3..e8482e1274794 100644 --- a/chrome/browser/net/profile_network_context_service.h +++ b/chrome/browser/net/profile_network_context_service.h @@ -132,6 +132,7 @@ class ProfileNetworkContextService std::string ComputeAcceptLanguage() const; void UpdateReferrersEnabled(); + void UpdateCrossOriginReferrerPolicy(); // Gets the current CTPolicy from preferences. network::mojom::CTPolicyPtr GetCTPolicy(); @@ -192,6 +193,7 @@ class ProfileNetworkContextService BooleanPrefMember quic_allowed_; StringPrefMember pref_accept_language_; BooleanPrefMember enable_referrers_; + IntegerPrefMember cross_origin_referrer_policy_; PrefChangeRegistrar pref_change_registrar_; scoped_refptr cookie_settings_; diff --git a/chrome/browser/renderer_preferences_util.cc b/chrome/browser/renderer_preferences_util.cc index 91192e62431b1..27bf3d8410d81 100644 --- a/chrome/browser/renderer_preferences_util.cc +++ b/chrome/browser/renderer_preferences_util.cc @@ -110,6 +110,9 @@ void UpdateFromSystemSettings(blink::RendererPreferences* prefs, prefs->accept_languages = GetLanguageListForProfile( profile, pref_service->GetString(language::prefs::kAcceptLanguages)); prefs->enable_referrers = pref_service->GetBoolean(prefs::kEnableReferrers); + prefs->cross_origin_referrer_policy = + static_cast( + pref_service->GetInteger(prefs::kCrossOriginReferrerPolicy)); prefs->enable_do_not_track = TrackingProtectionSettingsFactory::GetForProfile(profile) ->IsDoNotTrackEnabled(); diff --git a/chrome/browser/ui/android/strings/android_chrome_ext_strings.grdp b/chrome/browser/ui/android/strings/android_chrome_ext_strings.grdp index 11457f2fbc577..97c468723891d 100644 --- a/chrome/browser/ui/android/strings/android_chrome_ext_strings.grdp +++ b/chrome/browser/ui/android/strings/android_chrome_ext_strings.grdp @@ -9,6 +9,19 @@ Don't persist tabs between browsing sessions + + + Cross-origin referrer policy + + + Default + + + Reduce cross-origin referrer + + + Disable cross-origin referrer + Open external links in incognito diff --git a/chrome/browser/ui/prefs/pref_watcher.cc b/chrome/browser/ui/prefs/pref_watcher.cc index ea104d567ce33..4770ffe28269a 100644 --- a/chrome/browser/ui/prefs/pref_watcher.cc +++ b/chrome/browser/ui/prefs/pref_watcher.cc @@ -93,6 +93,8 @@ PrefWatcher::PrefWatcher(Profile* profile) renderer_callback); profile_pref_change_registrar_.Add(prefs::kEnableReferrers, renderer_callback); + profile_pref_change_registrar_.Add(prefs::kCrossOriginReferrerPolicy, + renderer_callback); profile_pref_change_registrar_.Add(prefs::kEnableEncryptedMedia, renderer_callback); profile_pref_change_registrar_.Add(prefs::kWebRTCIPHandlingPolicy, diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index aea2708b9c97a..f5a138449c2df 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -1456,6 +1456,10 @@ inline constexpr char kEnableHyperlinkAuditing[] = "enable_a_ping"; // Whether to enable sending referrers. inline constexpr char kEnableReferrers[] = "enable_referrers"; +// Preference to configure what referrers are sent cross-origin. +inline constexpr char kCrossOriginReferrerPolicy[] = + "cross_origin_referrer_policy"; + // Whether to allow the use of Encrypted Media Extensions (EME), except for the // use of Clear Key key sytems, which is always allowed as required by the spec. // TODO(crbug.com/784675): This pref was used as a WebPreference which is why diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc index 8ba07ea436976..9e1e8b31d7c34 100644 --- a/content/browser/renderer_host/navigation_request.cc +++ b/content/browser/renderer_host/navigation_request.cc @@ -393,6 +393,29 @@ void AddAdditionalRequestHeaders( blink::mojom::Referrer(GURL(), network::mojom::ReferrerPolicy::kNever); } + // Enforce cross-origin referrer policy + switch (render_prefs.cross_origin_referrer_policy) { + case network::mojom::CrossOriginReferrerPolicy::kDefault: + break; + case network::mojom::CrossOriginReferrerPolicy::kReduce: { + if (!referrer->url.is_empty() && + !url::IsSameOriginWith(url, referrer->url)) { + auto capped_referrer = url::Origin::Create(referrer->url); + *referrer = blink::mojom::Referrer(capped_referrer.GetURL(), + network::mojom::ReferrerPolicy::kOriginWhenCrossOrigin); + } + break; + } + case network::mojom::CrossOriginReferrerPolicy::kDisable: { + if (!referrer->url.is_empty() && + !url::IsSameOriginWith(url, referrer->url)) { + *referrer = blink::mojom::Referrer(GURL(), + network::mojom::ReferrerPolicy::kSameOrigin); + } + break; + } + } + // Next, set the HTTP Origin if needed. if (NeedsHTTPOrigin(headers, method)) { url::Origin origin_header_value = initiator_origin.value_or(url::Origin()); diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 47a2bc8e75e24..819e7a5f81ed1 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc @@ -4307,6 +4307,31 @@ void RenderFrameImpl::WillSendRequestInternal( request.SetReferrerString(WebString()); request.SetReferrerPolicy(network::mojom::ReferrerPolicy::kNever); } + + // Enforce cross-origin referrer policy + switch (GetWebView()->GetRendererPreferences().cross_origin_referrer_policy) { + case network::mojom::CrossOriginReferrerPolicy::kDefault: + break; + case network::mojom::CrossOriginReferrerPolicy::kReduce: { + GURL referrer_url = GURL(request.ReferrerString().Utf8()); + if (!referrer_url.is_empty() && + !url::IsSameOriginWith(request.Url(), referrer_url)) { + auto capped_referrer = url::Origin::Create(referrer_url); + request.SetReferrerString(WebString::FromUTF8(capped_referrer.GetURL().spec())); + request.SetReferrerPolicy(network::mojom::ReferrerPolicy::kOriginWhenCrossOrigin); + } + break; + } + case network::mojom::CrossOriginReferrerPolicy::kDisable: { + GURL referrer_url = GURL(request.ReferrerString().Utf8()); + if (!referrer_url.is_empty() && + !url::IsSameOriginWith(request.Url(), referrer_url)) { + request.SetReferrerString(WebString()); + request.SetReferrerPolicy(network::mojom::ReferrerPolicy::kSameOrigin); + } + break; + } + } } void RenderFrameImpl::DidLoadResourceFromMemoryCache( diff --git a/services/network/network_context.cc b/services/network/network_context.cc index 0a0fa8772cab9..08339f127f52a 100644 --- a/services/network/network_context.cc +++ b/services/network/network_context.cc @@ -1467,6 +1467,15 @@ void NetworkContext::SetEnableReferrers(bool enable_referrers) { network_delegate_->set_enable_referrers(enable_referrers); } +void NetworkContext::SetCrossOriginReferrerPolicy( + mojom::CrossOriginReferrerPolicy cross_origin_referrer_policy) { + // This may only be called on NetworkContexts created with the constructor + // that calls MakeURLRequestContext(). + DCHECK(network_delegate_); + network_delegate_->set_cross_origin_referrer_policy( + cross_origin_referrer_policy); +} + #if BUILDFLAG(IS_CHROMEOS) void NetworkContext::UpdateAdditionalCertificates( mojom::AdditionalCertificatesPtr additional_certificates) { @@ -2478,6 +2487,7 @@ URLRequestContextOwner NetworkContext::MakeURLRequestContext( std::unique_ptr network_delegate = std::make_unique( params_->enable_referrers, + params_->cross_origin_referrer_policy, params_->validate_referrer_policy_on_initial_request, std::move(params_->proxy_error_client), this); network_delegate_ = network_delegate.get(); diff --git a/services/network/network_context.h b/services/network/network_context.h index ef4140d740e23..86b2094011cc5 100644 --- a/services/network/network_context.h +++ b/services/network/network_context.h @@ -57,6 +57,7 @@ #include "services/network/public/mojom/cookie_manager.mojom-shared.h" #include "services/network/public/mojom/host_resolver.mojom.h" #include "services/network/public/mojom/network_context.mojom-forward.h" +#include "services/network/public/mojom/network_context.mojom-shared.h" #include "services/network/public/mojom/network_context.mojom.h" #include "services/network/public/mojom/network_service.mojom-forward.h" #include "services/network/public/mojom/proxy_lookup_client.mojom.h" @@ -315,6 +316,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext mojom::NetworkConditionsPtr conditions) override; void SetAcceptLanguage(const std::string& new_accept_language) override; void SetEnableReferrers(bool enable_referrers) override; + void SetCrossOriginReferrerPolicy( + mojom::CrossOriginReferrerPolicy cross_origin_referrer_policy) override; #if BUILDFLAG(IS_CHROMEOS) void UpdateAdditionalCertificates( mojom::AdditionalCertificatesPtr additional_certificates) override; diff --git a/services/network/network_service_network_delegate.cc b/services/network/network_service_network_delegate.cc index 82829ecd40058..646d2ddfa4798 100644 --- a/services/network/network_service_network_delegate.cc +++ b/services/network/network_service_network_delegate.cc @@ -37,10 +37,12 @@ namespace network { NetworkServiceNetworkDelegate::NetworkServiceNetworkDelegate( bool enable_referrers, + mojom::CrossOriginReferrerPolicy cross_origin_referrer_policy, bool validate_referrer_policy_on_initial_request, mojo::PendingRemote proxy_error_client_remote, NetworkContext* network_context) : enable_referrers_(enable_referrers), + cross_origin_referrer_policy_(cross_origin_referrer_policy), validate_referrer_policy_on_initial_request_( validate_referrer_policy_on_initial_request), network_context_(network_context) { @@ -59,12 +61,39 @@ void NetworkServiceNetworkDelegate::MaybeTruncateReferrer( return; } + // Enforce cross-origin referrer policy + switch (cross_origin_referrer_policy_) { + case mojom::CrossOriginReferrerPolicy::kDefault: { if (base::FeatureList::IsEnabled( net::features::kCapReferrerToOriginOnCrossOrigin)) { if (!url::IsSameOriginWith(effective_url, GURL(request->referrer()))) { auto capped_referrer = url::Origin::Create(GURL(request->referrer())); request->SetReferrer(capped_referrer.GetURL().spec()); } + } + break; + } + case mojom::CrossOriginReferrerPolicy::kReduce: { + GURL referrer_url = GURL(request->referrer()); + if (!referrer_url.is_empty() && + !url::IsSameOriginWith(effective_url, referrer_url)) { + auto capped_referrer = url::Origin::Create(referrer_url); + request->SetReferrer(capped_referrer.GetURL().spec()); + request->set_referrer_policy( + net::ReferrerPolicy::REDUCE_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN); + } + break; + } + case mojom::CrossOriginReferrerPolicy::kDisable: { + GURL referrer_url = GURL(request->referrer()); + if (!referrer_url.is_empty() && + !url::IsSameOriginWith(effective_url, referrer_url)) { + request->SetReferrer(std::string()); + request->set_referrer_policy( + net::ReferrerPolicy::CLEAR_ON_TRANSITION_CROSS_ORIGIN); + } + break; + } } } diff --git a/services/network/network_service_network_delegate.h b/services/network/network_service_network_delegate.h index cfcd91f7e47e4..0464219210160 100644 --- a/services/network/network_service_network_delegate.h +++ b/services/network/network_service_network_delegate.h @@ -16,6 +16,7 @@ #include "net/first_party_sets/first_party_sets_cache_filter.h" #include "services/network/cookie_settings.h" #include "services/network/network_context.h" +#include "services/network/public/mojom/network_context.mojom-shared.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace net { @@ -32,6 +33,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkServiceNetworkDelegate // |network_context| is guaranteed to outlive this class. NetworkServiceNetworkDelegate( bool enable_referrers, + mojom::CrossOriginReferrerPolicy cross_origin_referrer_policy, bool validate_referrer_policy_on_initial_request, mojo::PendingRemote proxy_error_client_remote, NetworkContext* network_context); @@ -46,6 +48,11 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkServiceNetworkDelegate enable_referrers_ = enable_referrers; } + void set_cross_origin_referrer_policy( + mojom::CrossOriginReferrerPolicy cross_origin_referrer_policy) { + cross_origin_referrer_policy_ = cross_origin_referrer_policy; + } + private: // net::NetworkDelegateImpl implementation. int OnBeforeURLRequest(net::URLRequest* request, @@ -113,6 +120,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkServiceNetworkDelegate const GURL& effective_url); bool enable_referrers_; + mojom::CrossOriginReferrerPolicy cross_origin_referrer_policy_; bool validate_referrer_policy_on_initial_request_; mojo::Remote proxy_error_client_; raw_ptr network_context_; diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom index 3d95f8cd1adeb..4ca34fbade5d5 100644 --- a/services/network/public/mojom/network_context.mojom +++ b/services/network/public/mojom/network_context.mojom @@ -316,6 +316,12 @@ struct NetworkContextFilePaths { bool trigger_migration = false; }; +enum CrossOriginReferrerPolicy { + kDefault, + kReduce, + kDisable, +}; + // Parameters for constructing a network context. struct NetworkContextParams { // The user agent string. @@ -335,6 +341,10 @@ struct NetworkContextParams { // If false, the referrer of requests is never populated. bool enable_referrers = true; + // Configures what referrers are sent cross-origin. + CrossOriginReferrerPolicy cross_origin_referrer_policy = + CrossOriginReferrerPolicy.kDefault; + // If true, requests initiated with referrers that don't match their referrer // policy will fail. bool validate_referrer_policy_on_initial_request = true; @@ -1232,6 +1242,10 @@ interface NetworkContext { // If false, the referrer of requests is never populated. SetEnableReferrers(bool enable_referrers); + // Updates the cross-origin referrer policy. + SetCrossOriginReferrerPolicy( + CrossOriginReferrerPolicy cross_origin_referrer_policy); + // Updates the additional trust anchors for certificate verification. [EnableIf=is_chromeos] UpdateAdditionalCertificates(AdditionalCertificates? additional_certificates); diff --git a/third_party/blink/common/renderer_preferences/renderer_preferences_mojom_traits.cc b/third_party/blink/common/renderer_preferences/renderer_preferences_mojom_traits.cc index 66f99b12ba32b..1a910ebc352c9 100644 --- a/third_party/blink/common/renderer_preferences/renderer_preferences_mojom_traits.cc +++ b/third_party/blink/common/renderer_preferences/renderer_preferences_mojom_traits.cc @@ -42,6 +42,7 @@ bool StructTraitsuse_custom_colors = data.use_custom_colors(); out->enable_referrers = data.enable_referrers(); + out->cross_origin_referrer_policy = data.cross_origin_referrer_policy(); out->allow_cross_origin_auth_prompt = data.allow_cross_origin_auth_prompt(); out->enable_do_not_track = data.enable_do_not_track(); out->enable_encrypted_media = data.enable_encrypted_media(); diff --git a/third_party/blink/public/common/renderer_preferences/renderer_preferences.h b/third_party/blink/public/common/renderer_preferences/renderer_preferences.h index ecda061e4a22b..59aaed7572fa7 100644 --- a/third_party/blink/public/common/renderer_preferences/renderer_preferences.h +++ b/third_party/blink/public/common/renderer_preferences/renderer_preferences.h @@ -12,6 +12,7 @@ #include "base/time/time.h" #include "build/build_config.h" +#include "services/network/public/mojom/network_context.mojom-shared.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/common_export.h" #include "third_party/blink/public/common/user_agent/user_agent_metadata.h" @@ -53,6 +54,9 @@ struct BLINK_COMMON_EXPORT RendererPreferences { absl::optional caret_blink_interval; bool use_custom_colors{true}; bool enable_referrers{true}; + network::mojom::CrossOriginReferrerPolicy cross_origin_referrer_policy { + network::mojom::CrossOriginReferrerPolicy::kDefault + }; bool allow_cross_origin_auth_prompt{false}; bool enable_do_not_track{false}; bool enable_encrypted_media{true}; diff --git a/third_party/blink/public/common/renderer_preferences/renderer_preferences_mojom_traits.h b/third_party/blink/public/common/renderer_preferences/renderer_preferences_mojom_traits.h index 8bbeee8821c39..488254d319810 100644 --- a/third_party/blink/public/common/renderer_preferences/renderer_preferences_mojom_traits.h +++ b/third_party/blink/public/common/renderer_preferences/renderer_preferences_mojom_traits.h @@ -107,6 +107,11 @@ struct BLINK_COMMON_EXPORT return data.enable_referrers; } + static const network::mojom::CrossOriginReferrerPolicy& + cross_origin_referrer_policy(const ::blink::RendererPreferences& data) { + return data.cross_origin_referrer_policy; + } + static const bool& allow_cross_origin_auth_prompt( const ::blink::RendererPreferences& data) { return data.allow_cross_origin_auth_prompt; diff --git a/third_party/blink/public/mojom/renderer_preferences.mojom b/third_party/blink/public/mojom/renderer_preferences.mojom index 271672f8a7a0b..a1da19a1e41c1 100644 --- a/third_party/blink/public/mojom/renderer_preferences.mojom +++ b/third_party/blink/public/mojom/renderer_preferences.mojom @@ -6,6 +6,7 @@ module blink.mojom; import "mojo/public/mojom/base/string16.mojom"; import "mojo/public/mojom/base/time.mojom"; +import "services/network/public/mojom/network_context.mojom"; import "ui/gfx/mojom/font_render_params.mojom"; import "third_party/blink/public/mojom/user_agent/user_agent_metadata.mojom"; @@ -70,6 +71,10 @@ struct RendererPreferences { // Set to false to not send referrers. bool enable_referrers = true; + // Configures what referrers are sent cross-origin + network.mojom.CrossOriginReferrerPolicy cross_origin_referrer_policy = + network.mojom.CrossOriginReferrerPolicy.kDefault; + // Set to true to allow third-party sub-content to pop-up HTTP basic auth // dialog boxes. bool allow_cross_origin_auth_prompt = false; diff --git a/third_party/blink/renderer/modules/service_worker/web_service_worker_fetch_context_impl.cc b/third_party/blink/renderer/modules/service_worker/web_service_worker_fetch_context_impl.cc index 247ea6ca9f7b3..2547438937e9a 100644 --- a/third_party/blink/renderer/modules/service_worker/web_service_worker_fetch_context_impl.cc +++ b/third_party/blink/renderer/modules/service_worker/web_service_worker_fetch_context_impl.cc @@ -156,6 +156,33 @@ void WebServiceWorkerFetchContextImpl::WillSendRequest(WebURLRequest& request) { request.SetReferrerString(WebString()); request.SetReferrerPolicy(network::mojom::ReferrerPolicy::kNever); } + + // Enforce cross-origin referrer policy + switch (renderer_preferences_.cross_origin_referrer_policy) { + case network::mojom::CrossOriginReferrerPolicy::kDefault: + break; + case network::mojom::CrossOriginReferrerPolicy::kReduce: { + KURL referrerUrl = KURL(request.ReferrerString()); + if (!referrerUrl.IsEmpty() && + !SecurityOrigin::AreSameOrigin(request.Url(), referrerUrl)) { + String originUrl = String( + SecurityOrigin::Create(referrerUrl)->ToUrlOrigin().GetURL().spec()); + request.SetReferrerString(originUrl); + request.SetReferrerPolicy( + network::mojom::ReferrerPolicy::kOriginWhenCrossOrigin); + } + break; + } + case network::mojom::CrossOriginReferrerPolicy::kDisable: { + KURL referrerUrl = KURL(request.ReferrerString()); + if (!referrerUrl.IsEmpty() && + !SecurityOrigin::AreSameOrigin(request.Url(), referrerUrl)) { + request.SetReferrerString(WebString()); + request.SetReferrerPolicy(network::mojom::ReferrerPolicy::kSameOrigin); + } + break; + } + } } WebVector> diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/dedicated_or_shared_worker_fetch_context_impl.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/dedicated_or_shared_worker_fetch_context_impl.cc index cb0b854156bb0..e0fef1e7df19f 100644 --- a/third_party/blink/renderer/platform/loader/fetch/url_loader/dedicated_or_shared_worker_fetch_context_impl.cc +++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/dedicated_or_shared_worker_fetch_context_impl.cc @@ -384,6 +384,33 @@ void DedicatedOrSharedWorkerFetchContextImpl::WillSendRequest( request.SetReferrerString(WebString()); request.SetReferrerPolicy(network::mojom::ReferrerPolicy::kNever); } + + // Enforce cross-origin referrer policy + switch (renderer_preferences_.cross_origin_referrer_policy) { + case network::mojom::CrossOriginReferrerPolicy::kDefault: + break; + case network::mojom::CrossOriginReferrerPolicy::kReduce: { + KURL referrerUrl = KURL(request.ReferrerString()); + if (!referrerUrl.IsEmpty() && + !SecurityOrigin::AreSameOrigin(request.Url(), referrerUrl)) { + String originUrl = String( + SecurityOrigin::Create(referrerUrl)->ToUrlOrigin().GetURL().spec()); + request.SetReferrerString(originUrl); + request.SetReferrerPolicy( + network::mojom::ReferrerPolicy::kOriginWhenCrossOrigin); + } + break; + } + case network::mojom::CrossOriginReferrerPolicy::kDisable: { + KURL referrerUrl = KURL(request.ReferrerString()); + if (!referrerUrl.IsEmpty() && + !SecurityOrigin::AreSameOrigin(request.Url(), referrerUrl)) { + request.SetReferrerString(WebString()); + request.SetReferrerPolicy(network::mojom::ReferrerPolicy::kSameOrigin); + } + break; + } + } } WebVector>