Bug 1620322 - Part 4: Refactor the code for the redirect heuristic out of AntiTrackingCommon.cpp; r=baku

Differential Revision: https://phabricator.services.mozilla.com/D65752

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Ehsan Akhgari 2020-03-09 18:12:30 +00:00
Родитель f658ede842
Коммит a1313db812
11 изменённых файлов: 260 добавлений и 204 удалений

Просмотреть файл

@ -63,7 +63,7 @@
#include "mozilla/ipc/URIUtils.h"
#include "mozilla/Telemetry.h"
#include "mozilla/Unused.h"
#include "mozilla/AntiTrackingCommon.h"
#include "mozilla/AntiTrackingRedirectHeuristic.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/LazyIdleThread.h"
#include "mozilla/SyncRunnable.h"
@ -838,7 +838,7 @@ nsresult nsHttpHandler::AsyncOnChannelRedirect(
newChan->GetURI(getter_AddRefs(newURI));
MOZ_ASSERT(newURI);
AntiTrackingCommon::RedirectHeuristic(oldChan, oldURI, newChan, newURI);
AntiTrackingRedirectHeuristic(oldChan, oldURI, newChan, newURI);
// TODO E10S This helper has to be initialized on the other process
RefPtr<nsAsyncRedirectVerifyHelper> redirectCallbackHelper =

Просмотреть файл

@ -45,7 +45,6 @@
#include "nsPIDOMWindow.h"
#include "nsPrintfCString.h"
#include "nsScriptSecurityManager.h"
#include "nsSandboxFlags.h"
#include "prtime.h"
#define ANTITRACKING_PERM_KEY "3rdPartyStorage"
@ -1422,200 +1421,3 @@ bool AntiTrackingCommon::HasUserInteraction(nsIPrincipal* aPrincipal) {
return result == nsIPermissionManager::ALLOW_ACTION;
}
/* static */
void AntiTrackingCommon::RedirectHeuristic(nsIChannel* aOldChannel,
nsIURI* aOldURI,
nsIChannel* aNewChannel,
nsIURI* aNewURI) {
MOZ_ASSERT(aOldChannel);
MOZ_ASSERT(aOldURI);
MOZ_ASSERT(aNewChannel);
MOZ_ASSERT(aNewURI);
nsresult rv;
if (!StaticPrefs::privacy_restrict3rdpartystorage_heuristic_redirect()) {
return;
}
nsCOMPtr<nsIHttpChannel> newChannel = do_QueryInterface(aNewChannel);
if (!newChannel) {
return;
}
LOG_SPEC(("Checking redirect-heuristic for %s", _spec), aOldURI);
nsCOMPtr<nsILoadInfo> oldLoadInfo = aOldChannel->LoadInfo();
MOZ_ASSERT(oldLoadInfo);
nsCOMPtr<nsILoadInfo> newLoadInfo = aNewChannel->LoadInfo();
MOZ_ASSERT(newLoadInfo);
nsContentPolicyType contentType = oldLoadInfo->GetExternalContentPolicyType();
if (contentType != nsIContentPolicy::TYPE_DOCUMENT ||
!aOldChannel->IsDocument()) {
LOG_SPEC(("Ignoring redirect for %s because it's not a document", _spec),
aOldURI);
// We care about document redirects only.
return;
}
nsCOMPtr<nsIClassifiedChannel> classifiedOldChannel =
do_QueryInterface(aOldChannel);
nsCOMPtr<nsIClassifiedChannel> classifiedNewChannel =
do_QueryInterface(aNewChannel);
if (!classifiedOldChannel || !classifiedNewChannel) {
LOG_SPEC2(("Ignoring redirect for %s to %s because there is not "
"nsIClassifiedChannel interface",
_spec1, _spec2),
aOldURI, aNewURI);
return;
}
bool allowedByPreviousRedirect =
oldLoadInfo->GetAllowListFutureDocumentsCreatedFromThisRedirectChain();
// We're looking at the first-party classification flags because we're
// interested in first-party redirects.
uint32_t newClassificationFlags =
classifiedNewChannel->GetFirstPartyClassificationFlags();
if (net::UrlClassifierCommon::IsTrackingClassificationFlag(
newClassificationFlags)) {
// This is not a tracking -> non-tracking redirect.
LOG_SPEC2(("Redirect for %s to %s because it's not tracking to "
"non-tracking. Part of a chain of granted redirects: %d",
_spec1, _spec2, allowedByPreviousRedirect),
aOldURI, aNewURI);
newLoadInfo->SetAllowListFutureDocumentsCreatedFromThisRedirectChain(
allowedByPreviousRedirect);
return;
}
uint32_t oldClassificationFlags =
classifiedOldChannel->GetFirstPartyClassificationFlags();
if (!net::UrlClassifierCommon::IsTrackingClassificationFlag(
oldClassificationFlags) &&
!allowedByPreviousRedirect) {
// This is not a tracking -> non-tracking redirect.
LOG_SPEC2(
("Redirect for %s to %s because it's not tracking to non-tracking.",
_spec1, _spec2),
aOldURI, aNewURI);
return;
}
nsIScriptSecurityManager* ssm =
nsScriptSecurityManager::GetScriptSecurityManager();
MOZ_ASSERT(ssm);
nsCOMPtr<nsIPrincipal> trackingPrincipal;
const nsTArray<nsCOMPtr<nsIRedirectHistoryEntry>>& chain =
oldLoadInfo->RedirectChain();
if (allowedByPreviousRedirect && !chain.IsEmpty()) {
rv = chain[0]->GetPrincipal(getter_AddRefs(trackingPrincipal));
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Can't obtain the principal from the redirect chain"));
return;
}
} else {
rv = ssm->GetChannelResultPrincipal(aOldChannel,
getter_AddRefs(trackingPrincipal));
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Can't obtain the principal from the tracking"));
return;
}
}
nsCOMPtr<nsIPrincipal> redirectedPrincipal;
rv = ssm->GetChannelResultPrincipal(aNewChannel,
getter_AddRefs(redirectedPrincipal));
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Can't obtain the principal from the redirected"));
return;
}
if (!AntiTrackingCommon::HasUserInteraction(trackingPrincipal)) {
LOG_SPEC2(("Ignoring redirect for %s to %s because no user-interaction on "
"tracker",
_spec1, _spec2),
aOldURI, aNewURI);
return;
}
nsAutoCString trackingOrigin;
rv = trackingPrincipal->GetOrigin(trackingOrigin);
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Can't get the origin from the Principal"));
return;
}
nsAutoCString redirectedOrigin;
rv = nsContentUtils::GetASCIIOrigin(aNewURI, redirectedOrigin);
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Can't get the origin from the URI"));
return;
}
LOG(("Adding a first-party storage exception for %s...",
PromiseFlatCString(redirectedOrigin).get()));
nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
rv = oldLoadInfo->GetCookieJarSettings(getter_AddRefs(cookieJarSettings));
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Can't get the cookieJarSettings"));
return;
}
int32_t behavior = cookieJarSettings->GetCookieBehavior();
if (!cookieJarSettings->GetRejectThirdPartyTrackers()) {
LOG(
("Disabled by network.cookie.cookieBehavior pref (%d), bailing out "
"early",
behavior));
return;
}
MOZ_ASSERT(
behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER ||
behavior ==
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN);
if (ContentBlockingAllowList::Check(newChannel)) {
return;
}
LOG(("Saving the permission: trackingOrigin=%s, grantedOrigin=%s",
trackingOrigin.get(), redirectedOrigin.get()));
// Any new redirect from this loadInfo must be considered as granted.
newLoadInfo->SetAllowListFutureDocumentsCreatedFromThisRedirectChain(true);
uint64_t innerWindowID;
Unused << newChannel->GetTopLevelContentWindowId(&innerWindowID);
nsAutoString errorText;
AutoTArray<nsString, 2> params = {NS_ConvertUTF8toUTF16(redirectedOrigin),
NS_ConvertUTF8toUTF16(trackingOrigin)};
rv = nsContentUtils::FormatLocalizedString(
nsContentUtils::eNECKO_PROPERTIES, "CookieAllowedForTrackerByHeuristic",
params, errorText);
if (NS_SUCCEEDED(rv)) {
nsContentUtils::ReportToConsoleByWindowID(
errorText, nsIScriptError::warningFlag, ANTITRACKING_CONSOLE_CATEGORY,
innerWindowID);
}
// We don't care about this promise because the operation is actually sync.
RefPtr<FirstPartyStorageAccessGrantPromise> promise =
SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(
redirectedPrincipal, trackingPrincipal, trackingOrigin,
StorageAccessPromptChoices::eAllow,
StaticPrefs::privacy_restrict3rdpartystorage_expiration_redirect());
Unused << promise;
}

Просмотреть файл

@ -123,9 +123,6 @@ class AntiTrackingCommon final {
const nsCString& aTrackingOrigin, int aAllowMode,
uint64_t aExpirationTime =
StaticPrefs::privacy_restrict3rdpartystorage_expiration());
static void RedirectHeuristic(nsIChannel* aOldChannel, nsIURI* aOldURI,
nsIChannel* aNewChannel, nsIURI* aNewURI);
};
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,222 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "AntiTrackingLog.h"
#include "AntiTrackingRedirectHeuristic.h"
#include "AntiTrackingCommon.h"
#include "ContentBlockingAllowList.h"
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/Document.h"
#include "mozilla/net/UrlClassifierCommon.h"
#include "nsContentUtils.h"
#include "nsIChannel.h"
#include "nsIClassifiedChannel.h"
#include "nsIRedirectHistoryEntry.h"
#include "nsIScriptError.h"
#include "nsIURI.h"
#include "nsPIDOMWindow.h"
#include "nsScriptSecurityManager.h"
namespace mozilla {
void AntiTrackingRedirectHeuristic(nsIChannel* aOldChannel, nsIURI* aOldURI,
nsIChannel* aNewChannel, nsIURI* aNewURI) {
MOZ_ASSERT(aOldChannel);
MOZ_ASSERT(aOldURI);
MOZ_ASSERT(aNewChannel);
MOZ_ASSERT(aNewURI);
nsresult rv;
if (!StaticPrefs::privacy_restrict3rdpartystorage_heuristic_redirect()) {
return;
}
nsCOMPtr<nsIHttpChannel> newChannel = do_QueryInterface(aNewChannel);
if (!newChannel) {
return;
}
LOG_SPEC(("Checking redirect-heuristic for %s", _spec), aOldURI);
nsCOMPtr<nsILoadInfo> oldLoadInfo = aOldChannel->LoadInfo();
MOZ_ASSERT(oldLoadInfo);
nsCOMPtr<nsILoadInfo> newLoadInfo = aNewChannel->LoadInfo();
MOZ_ASSERT(newLoadInfo);
nsContentPolicyType contentType = oldLoadInfo->GetExternalContentPolicyType();
if (contentType != nsIContentPolicy::TYPE_DOCUMENT ||
!aOldChannel->IsDocument()) {
LOG_SPEC(("Ignoring redirect for %s because it's not a document", _spec),
aOldURI);
// We care about document redirects only.
return;
}
nsCOMPtr<nsIClassifiedChannel> classifiedOldChannel =
do_QueryInterface(aOldChannel);
nsCOMPtr<nsIClassifiedChannel> classifiedNewChannel =
do_QueryInterface(aNewChannel);
if (!classifiedOldChannel || !classifiedNewChannel) {
LOG_SPEC2(("Ignoring redirect for %s to %s because there is not "
"nsIClassifiedChannel interface",
_spec1, _spec2),
aOldURI, aNewURI);
return;
}
bool allowedByPreviousRedirect =
oldLoadInfo->GetAllowListFutureDocumentsCreatedFromThisRedirectChain();
// We're looking at the first-party classification flags because we're
// interested in first-party redirects.
uint32_t newClassificationFlags =
classifiedNewChannel->GetFirstPartyClassificationFlags();
if (net::UrlClassifierCommon::IsTrackingClassificationFlag(
newClassificationFlags)) {
// This is not a tracking -> non-tracking redirect.
LOG_SPEC2(("Redirect for %s to %s because it's not tracking to "
"non-tracking. Part of a chain of granted redirects: %d",
_spec1, _spec2, allowedByPreviousRedirect),
aOldURI, aNewURI);
newLoadInfo->SetAllowListFutureDocumentsCreatedFromThisRedirectChain(
allowedByPreviousRedirect);
return;
}
uint32_t oldClassificationFlags =
classifiedOldChannel->GetFirstPartyClassificationFlags();
if (!net::UrlClassifierCommon::IsTrackingClassificationFlag(
oldClassificationFlags) &&
!allowedByPreviousRedirect) {
// This is not a tracking -> non-tracking redirect.
LOG_SPEC2(
("Redirect for %s to %s because it's not tracking to non-tracking.",
_spec1, _spec2),
aOldURI, aNewURI);
return;
}
nsIScriptSecurityManager* ssm =
nsScriptSecurityManager::GetScriptSecurityManager();
MOZ_ASSERT(ssm);
nsCOMPtr<nsIPrincipal> trackingPrincipal;
const nsTArray<nsCOMPtr<nsIRedirectHistoryEntry>>& chain =
oldLoadInfo->RedirectChain();
if (allowedByPreviousRedirect && !chain.IsEmpty()) {
rv = chain[0]->GetPrincipal(getter_AddRefs(trackingPrincipal));
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Can't obtain the principal from the redirect chain"));
return;
}
} else {
rv = ssm->GetChannelResultPrincipal(aOldChannel,
getter_AddRefs(trackingPrincipal));
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Can't obtain the principal from the tracking"));
return;
}
}
nsCOMPtr<nsIPrincipal> redirectedPrincipal;
rv = ssm->GetChannelResultPrincipal(aNewChannel,
getter_AddRefs(redirectedPrincipal));
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Can't obtain the principal from the redirected"));
return;
}
if (!AntiTrackingCommon::HasUserInteraction(trackingPrincipal)) {
LOG_SPEC2(("Ignoring redirect for %s to %s because no user-interaction on "
"tracker",
_spec1, _spec2),
aOldURI, aNewURI);
return;
}
nsAutoCString trackingOrigin;
rv = trackingPrincipal->GetOrigin(trackingOrigin);
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Can't get the origin from the Principal"));
return;
}
nsAutoCString redirectedOrigin;
rv = nsContentUtils::GetASCIIOrigin(aNewURI, redirectedOrigin);
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Can't get the origin from the URI"));
return;
}
LOG(("Adding a first-party storage exception for %s...",
PromiseFlatCString(redirectedOrigin).get()));
nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
rv = oldLoadInfo->GetCookieJarSettings(getter_AddRefs(cookieJarSettings));
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Can't get the cookieJarSettings"));
return;
}
int32_t behavior = cookieJarSettings->GetCookieBehavior();
if (!cookieJarSettings->GetRejectThirdPartyTrackers()) {
LOG(
("Disabled by network.cookie.cookieBehavior pref (%d), bailing out "
"early",
behavior));
return;
}
MOZ_ASSERT(
behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER ||
behavior ==
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN);
if (ContentBlockingAllowList::Check(newChannel)) {
return;
}
LOG(("Saving the permission: trackingOrigin=%s, grantedOrigin=%s",
trackingOrigin.get(), redirectedOrigin.get()));
// Any new redirect from this loadInfo must be considered as granted.
newLoadInfo->SetAllowListFutureDocumentsCreatedFromThisRedirectChain(true);
uint64_t innerWindowID;
Unused << newChannel->GetTopLevelContentWindowId(&innerWindowID);
nsAutoString errorText;
AutoTArray<nsString, 2> params = {NS_ConvertUTF8toUTF16(redirectedOrigin),
NS_ConvertUTF8toUTF16(trackingOrigin)};
rv = nsContentUtils::FormatLocalizedString(
nsContentUtils::eNECKO_PROPERTIES, "CookieAllowedForTrackerByHeuristic",
params, errorText);
if (NS_SUCCEEDED(rv)) {
nsContentUtils::ReportToConsoleByWindowID(
errorText, nsIScriptError::warningFlag, ANTITRACKING_CONSOLE_CATEGORY,
innerWindowID);
}
// We don't care about this promise because the operation is actually sync.
RefPtr<AntiTrackingCommon::FirstPartyStorageAccessGrantPromise> promise =
AntiTrackingCommon::
SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(
redirectedPrincipal, trackingPrincipal, trackingOrigin,
AntiTrackingCommon::StorageAccessPromptChoices::eAllow,
StaticPrefs::
privacy_restrict3rdpartystorage_expiration_redirect());
Unused << promise;
}
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,20 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_antitrackingredirectheuristic_h
#define mozilla_antitrackingredirectheuristic_h
class nsIChannel;
class nsIURI;
namespace mozilla {
void AntiTrackingRedirectHeuristic(nsIChannel* aOldChannel, nsIURI* aOldURI,
nsIChannel* aNewChannel, nsIURI* aNewURI);
} // namespace mozilla
#endif // mozilla_antitrackingredirectheuristic_h

Просмотреть файл

@ -11,6 +11,8 @@
class nsPIDOMWindowInner;
class nsPIDOMWindowOuter;
class nsIChannel;
class nsIURI;
namespace mozilla {

Просмотреть файл

@ -26,6 +26,8 @@ class ContentBlockingAllowList final {
static nsresult Check(nsIPrincipal* aContentBlockingAllowListPrincipal,
bool aIsPrivateBrowsing, bool& aIsAllowListed);
static bool Check(nsIHttpChannel* aChannel);
// Computes the principal used to check the content blocking allow list for a
// top-level document based on the document principal. This function is used
// right after setting up the document principal.
@ -44,7 +46,6 @@ class ContentBlockingAllowList final {
// Utility APIs for AntiTrackingCommon.
static bool Check(nsIPrincipal* aTopWinPrincipal, bool aIsPrivateBrowsing);
static bool Check(nsPIDOMWindowInner* aWindow);
static bool Check(nsIHttpChannel* aChannel);
friend class AntiTrackingCommon;
};

Просмотреть файл

@ -11,9 +11,16 @@
#include "mozilla/StaticPrefs_network.h"
#include "mozilla/StaticPrefs_privacy.h"
#include "mozilla/StorageAccess.h"
#include "nsContentUtils.h"
#include "nsICookiePermission.h"
#include "nsICookieService.h"
#include "nsICookieJarSettings.h"
#include "nsIPermission.h"
#include "nsIWebProgressListener.h"
#include "nsSandboxFlags.h"
using namespace mozilla;
using namespace mozilla::dom;
/**
* Gets the cookie lifetime policy for a given cookieJarSettings and a given

Просмотреть файл

@ -7,6 +7,8 @@
#ifndef mozilla_StoragePrincipalHelper_h
#define mozilla_StoragePrincipalHelper_h
#include "nsError.h"
/**
* StoragePrincipal
* ~~~~~~~~~~~~~~~~

Просмотреть файл

@ -10,6 +10,7 @@
#include "mozilla/Preferences.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsEffectiveTLDService.h"
#include "nsIURI.h"
#include "nsIURIMutator.h"
namespace {

Просмотреть файл

@ -33,6 +33,7 @@ XPCOM_MANIFESTS += [
EXPORTS.mozilla = [
'AntiTrackingCommon.h',
'AntiTrackingIPCUtils.h',
'AntiTrackingRedirectHeuristic.h',
'AntiTrackingUtils.h',
'ContentBlockingAllowList.h',
'ContentBlockingNotifier.h',
@ -43,6 +44,7 @@ EXPORTS.mozilla = [
UNIFIED_SOURCES += [
'AntiTrackingCommon.cpp',
'AntiTrackingRedirectHeuristic.cpp',
'AntiTrackingUtils.cpp',
'ContentBlockingAllowList.cpp',
'ContentBlockingNotifier.cpp',