Bug 1876575, part 1 - Make AntiTracking::IsThirdParty* aware of ABA case - r=anti-tracking-reviewers,cookie-reviewers,timhuang

Differential Revision: https://phabricator.services.mozilla.com/D203180
This commit is contained in:
Benjamin VanderSloot 2024-04-02 18:53:26 +00:00
parent d3ef19887a
commit ba265bda60
5 changed files with 105 additions and 63 deletions

View file

@ -4,9 +4,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozIThirdPartyUtil.h"
#include "mozilla/AntiTrackingUtils.h" #include "mozilla/AntiTrackingUtils.h"
#include "mozilla/BasePrincipal.h" #include "mozilla/BasePrincipal.h"
#include "mozilla/ClearOnShutdown.h" #include "mozilla/ClearOnShutdown.h"
#include "mozilla/Components.h"
#include "mozilla/ContentBlockingAllowList.h" #include "mozilla/ContentBlockingAllowList.h"
#include "mozilla/dom/BrowsingContext.h" #include "mozilla/dom/BrowsingContext.h"
#include "mozilla/net/CookieJarSettings.h" #include "mozilla/net/CookieJarSettings.h"
@ -539,10 +541,9 @@ void CookieJarSettings::SetPartitionKey(nsIURI* aURI,
void CookieJarSettings::UpdatePartitionKeyForDocumentLoadedByChannel( void CookieJarSettings::UpdatePartitionKeyForDocumentLoadedByChannel(
nsIChannel* aChannel) { nsIChannel* aChannel) {
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo(); nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
bool thirdParty = AntiTrackingUtils::IsThirdPartyChannel(aChannel);
bool foreignByAncestorContext = bool foreignByAncestorContext =
false; // Bug 1876575 will change this to thirdParty && !loadInfo->GetIsThirdPartyContextToTopWindow();
// loadInfo->GetIsInThirdPartyContext() &&
// !loadInfo->GetIsThirdPartyContextToTopWindow();
StoragePrincipalHelper::UpdatePartitionKeyWithForeignAncestorBit( StoragePrincipalHelper::UpdatePartitionKeyWithForeignAncestorBit(
mPartitionKey, foreignByAncestorContext); mPartitionKey, foreignByAncestorContext);
} }

View file

@ -825,7 +825,8 @@ void AntiTrackingUtils::ComputeIsThirdPartyToTopWindow(nsIChannel* aChannel) {
// whether the page is third-party, so we use channel result principal // whether the page is third-party, so we use channel result principal
// instead. By doing this, an the resource inherits the principal from // instead. By doing this, an the resource inherits the principal from
// its parent is considered not a third-party. // its parent is considered not a third-party.
if (NS_IsAboutBlank(uri) || NS_IsAboutSrcdoc(uri)) { if (NS_IsAboutBlank(uri) || NS_IsAboutSrcdoc(uri) ||
uri->SchemeIs("blob")) {
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
if (NS_WARN_IF(!ssm)) { if (NS_WARN_IF(!ssm)) {
return; return;
@ -851,10 +852,36 @@ void AntiTrackingUtils::ComputeIsThirdPartyToTopWindow(nsIChannel* aChannel) {
bool AntiTrackingUtils::IsThirdPartyChannel(nsIChannel* aChannel) { bool AntiTrackingUtils::IsThirdPartyChannel(nsIChannel* aChannel) {
MOZ_ASSERT(aChannel); MOZ_ASSERT(aChannel);
// We only care whether the channel is 3rd-party with respect to // We have to handle blob URLs here because they always fail
// the top-level. // IsThirdPartyChannel because of how blob URLs are constructed. We just
// recompare to their ancestor chain from the loadInfo, bailing if any is
// third party.
nsAutoCString scheme;
nsCOMPtr<nsIURI> channelURI;
nsresult rv = aChannel->GetURI(getter_AddRefs(channelURI));
if (NS_SUCCEEDED(rv) && channelURI->SchemeIs("blob")) {
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo(); nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
return loadInfo->GetIsThirdPartyContextToTopWindow(); for (const nsCOMPtr<nsIPrincipal>& principal :
loadInfo->AncestorPrincipals()) {
bool thirdParty = true;
rv = loadInfo->PrincipalToInherit()->IsThirdPartyPrincipal(principal,
&thirdParty);
if (NS_SUCCEEDED(rv) && thirdParty) {
return true;
}
}
return false;
}
nsCOMPtr<mozIThirdPartyUtil> tpuService =
mozilla::components::ThirdPartyUtil::Service();
if (!tpuService) {
return true;
}
bool thirdParty = true;
rv = tpuService->IsThirdPartyChannel(aChannel, nullptr, &thirdParty);
NS_ENSURE_SUCCESS(rv, true);
return thirdParty;
} }
/* static */ /* static */
@ -907,19 +934,29 @@ bool AntiTrackingUtils::IsThirdPartyWindow(nsPIDOMWindowInner* aWindow,
/* static */ /* static */
bool AntiTrackingUtils::IsThirdPartyDocument(Document* aDocument) { bool AntiTrackingUtils::IsThirdPartyDocument(Document* aDocument) {
MOZ_ASSERT(aDocument); MOZ_ASSERT(aDocument);
if (!aDocument->GetChannel()) { nsCOMPtr<mozIThirdPartyUtil> tpuService =
mozilla::components::ThirdPartyUtil::Service();
if (!tpuService) {
return true;
}
bool thirdParty = true;
if (!aDocument->GetChannel() ||
aDocument->GetDocumentURI()->SchemeIs("blob")) {
// If we can't get the channel from the document, i.e. initial about:blank // If we can't get the channel from the document, i.e. initial about:blank
// page, we use the browsingContext of the document to check if it's in the // page, we use the browsingContext of the document to check if it's in the
// third-party context. If the browsing context is still not available, we // third-party context. If the browsing context is still not available, we
// will treat the window as third-party. // will treat the window as third-party.
// We also rely on IsThirdPartyContext for blob documents because the
// IsThirdPartyChannel check relies on getting the BaseDomain,
// which correctly fails for blobs URIs.
RefPtr<BrowsingContext> bc = aDocument->GetBrowsingContext(); RefPtr<BrowsingContext> bc = aDocument->GetBrowsingContext();
return bc ? IsThirdPartyContext(bc) : true; return bc ? IsThirdPartyContext(bc) : true;
} }
// We only care whether the channel is 3rd-party with respect to nsresult rv = tpuService->IsThirdPartyChannel(aDocument->GetChannel(),
// the top-level. nullptr, &thirdParty);
nsCOMPtr<nsILoadInfo> loadInfo = aDocument->GetChannel()->LoadInfo(); NS_ENSURE_SUCCESS(rv, true);
return loadInfo->GetIsThirdPartyContextToTopWindow(); return thirdParty;
} }
/* static */ /* static */
@ -927,41 +964,47 @@ bool AntiTrackingUtils::IsThirdPartyContext(BrowsingContext* aBrowsingContext) {
MOZ_ASSERT(aBrowsingContext); MOZ_ASSERT(aBrowsingContext);
MOZ_ASSERT(aBrowsingContext->IsInProcess()); MOZ_ASSERT(aBrowsingContext->IsInProcess());
if (aBrowsingContext->IsTopContent()) { // iframes with SANDBOX_ORIGIN are always third-party contexts
return false; // because they are a unique origin
}
// If the top browsing context is not in the same process, it's cross-origin.
if (!aBrowsingContext->Top()->IsInProcess()) {
return true;
}
nsIDocShell* docShell = aBrowsingContext->GetDocShell(); nsIDocShell* docShell = aBrowsingContext->GetDocShell();
if (!docShell) { if (!docShell) {
return true; return true;
} }
Document* doc = docShell->GetExtantDocument(); Document* doc = docShell->GetExtantDocument();
if (!doc) { if (!doc || doc->GetSandboxFlags() & SANDBOXED_ORIGIN) {
return true; return true;
} }
nsIPrincipal* principal = doc->NodePrincipal(); nsIPrincipal* principal = doc->NodePrincipal();
nsIDocShell* topDocShell = aBrowsingContext->Top()->GetDocShell(); BrowsingContext* traversingParent = aBrowsingContext->GetParent();
if (!topDocShell) { while (traversingParent) {
// If the parent browsing context is not in the same process, it's
// cross-origin.
if (!traversingParent->IsInProcess()) {
return true; return true;
} }
Document* topDoc = topDocShell->GetDocument();
if (!topDoc) {
return true;
}
nsIPrincipal* topPrincipal = topDoc->NodePrincipal();
auto* topBasePrin = BasePrincipal::Cast(topPrincipal); nsIDocShell* parentDocShell = traversingParent->GetDocShell();
if (!parentDocShell) {
return true;
}
Document* parentDoc = parentDocShell->GetDocument();
if (!parentDoc || parentDoc->GetSandboxFlags() & SANDBOXED_ORIGIN) {
return true;
}
nsIPrincipal* parentPrincipal = parentDoc->NodePrincipal();
auto* parentBasePrin = BasePrincipal::Cast(parentPrincipal);
bool isThirdParty = true; bool isThirdParty = true;
topBasePrin->IsThirdPartyPrincipal(principal, &isThirdParty); parentBasePrin->IsThirdPartyPrincipal(principal, &isThirdParty);
if (isThirdParty) {
return true;
}
return isThirdParty; traversingParent = traversingParent->GetParent();
}
return false;
} }
/* static */ /* static */
@ -1009,6 +1052,9 @@ void AntiTrackingUtils::UpdateAntiTrackingInfoForChannel(nsIChannel* aChannel) {
->MarkOverriddenFingerprintingSettingsAsSet(); ->MarkOverriddenFingerprintingSettingsAsSet();
#endif #endif
ExtContentPolicyType contentType = loadInfo->GetExternalContentPolicyType();
if (contentType == ExtContentPolicy::TYPE_DOCUMENT ||
contentType == ExtContentPolicy::TYPE_SUBDOCUMENT) {
nsCOMPtr<nsICookieJarSettings> cookieJarSettings; nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
Unused << loadInfo->GetCookieJarSettings(getter_AddRefs(cookieJarSettings)); Unused << loadInfo->GetCookieJarSettings(getter_AddRefs(cookieJarSettings));
// For subdocuments, the channel's partition key is that of the parent // For subdocuments, the channel's partition key is that of the parent
@ -1016,6 +1062,7 @@ void AntiTrackingUtils::UpdateAntiTrackingInfoForChannel(nsIChannel* aChannel) {
// one without the same-site bit. // one without the same-site bit.
net::CookieJarSettings::Cast(cookieJarSettings) net::CookieJarSettings::Cast(cookieJarSettings)
->UpdatePartitionKeyForDocumentLoadedByChannel(aChannel); ->UpdatePartitionKeyForDocumentLoadedByChannel(aChannel);
}
// We only update the IsOnContentBlockingAllowList flag and the partition key // We only update the IsOnContentBlockingAllowList flag and the partition key
// for the top-level http channel. // for the top-level http channel.
@ -1027,14 +1074,15 @@ void AntiTrackingUtils::UpdateAntiTrackingInfoForChannel(nsIChannel* aChannel) {
// The partition key is computed based on the site, so it's no point to set it // The partition key is computed based on the site, so it's no point to set it
// for channels other than http channels. // for channels other than http channels.
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel); nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
if (!httpChannel || loadInfo->GetExternalContentPolicyType() != if (!httpChannel || contentType != ExtContentPolicy::TYPE_DOCUMENT) {
ExtContentPolicy::TYPE_DOCUMENT) {
return; return;
} }
// Update the IsOnContentBlockingAllowList flag in the CookieJarSettings // Update the IsOnContentBlockingAllowList flag in the CookieJarSettings
// if this is a top level loading. For sub-document loading, this flag // if this is a top level loading. For sub-document loading, this flag
// would inherit from the parent. // would inherit from the parent.
nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
Unused << loadInfo->GetCookieJarSettings(getter_AddRefs(cookieJarSettings));
net::CookieJarSettings::Cast(cookieJarSettings) net::CookieJarSettings::Cast(cookieJarSettings)
->UpdateIsOnContentBlockingAllowList(aChannel); ->UpdateIsOnContentBlockingAllowList(aChannel);

View file

@ -475,7 +475,6 @@ StorageAccessAPIHelper::CompleteAllowAccessForOnParentProcess(
[aParentContext, aTopLevelWindowId, trackingOrigin, trackingPrincipal, [aParentContext, aTopLevelWindowId, trackingOrigin, trackingPrincipal,
aCookieBehavior, aCookieBehavior,
aReason](int aAllowMode) -> RefPtr<StorageAccessPermissionGrantPromise> { aReason](int aAllowMode) -> RefPtr<StorageAccessPermissionGrantPromise> {
MOZ_ASSERT(!aParentContext->IsInProcess());
// We don't have the window, send an IPC to the content process that // We don't have the window, send an IPC to the content process that
// owns the parent window. But there is a special case, for window.open, // owns the parent window. But there is a special case, for window.open,
// we'll return to the content process we need to inform when this // we'll return to the content process we need to inform when this
@ -1060,12 +1059,7 @@ StorageAccessAPIHelper::CheckSameSiteCallingContextDecidesStorageAccessAPI(
} }
} }
nsIChannel* chan = aDocument->GetChannel(); if (AntiTrackingUtils::IsThirdPartyDocument(aDocument)) {
if (!chan) {
return Some(false);
}
nsCOMPtr<nsILoadInfo> loadInfo = chan->LoadInfo();
if (loadInfo->GetIsThirdPartyContextToTopWindow()) {
return Some(false); return Some(false);
} }

View file

@ -87,9 +87,8 @@ bool ChooseOriginAttributes(nsIChannel* aChannel, OriginAttributes& aAttrs,
return false; return false;
} }
bool foreignByAncestorContext = bool foreignByAncestorContext =
false; // Bug 1876575 will change this to AntiTrackingUtils::IsThirdPartyChannel(aChannel) &&
// loadInfo->GetIsInThirdPartyContext() && !loadInfo->GetIsThirdPartyContextToTopWindow();
// !loadInfo->GetIsThirdPartyContextToTopWindow();
aAttrs.SetPartitionKey(principalURI, foreignByAncestorContext); aAttrs.SetPartitionKey(principalURI, foreignByAncestorContext);
return true; return true;
} }
@ -316,7 +315,7 @@ nsresult StoragePrincipalHelper::GetPrincipal(nsIChannel* aChannel,
// We only support foreign partitioned principal when dFPI is enabled. // We only support foreign partitioned principal when dFPI is enabled.
if (cjs->GetCookieBehavior() == if (cjs->GetCookieBehavior() ==
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN && nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN &&
loadInfo->GetIsThirdPartyContextToTopWindow()) { AntiTrackingUtils::IsThirdPartyChannel(aChannel)) {
outPrincipal = partitionedPrincipal; outPrincipal = partitionedPrincipal;
} }
break; break;
@ -482,7 +481,7 @@ bool StoragePrincipalHelper::GetOriginAttributes(
// Otherwise, we will use the regular principal. // Otherwise, we will use the regular principal.
if (cjs->GetCookieBehavior() == if (cjs->GetCookieBehavior() ==
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN && nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN &&
loadInfo->GetIsThirdPartyContextToTopWindow()) { AntiTrackingUtils::IsThirdPartyChannel(aChannel)) {
ChooseOriginAttributes(aChannel, aAttributes, true); ChooseOriginAttributes(aChannel, aAttributes, true);
} }
break; break;

View file

@ -19,6 +19,7 @@
#include "MainThreadUtils.h" #include "MainThreadUtils.h"
#include "ScopedNSSTypes.h" #include "ScopedNSSTypes.h"
#include "mozilla/AntiTrackingUtils.h"
#include "mozilla/ArrayIterator.h" #include "mozilla/ArrayIterator.h"
#include "mozilla/Assertions.h" #include "mozilla/Assertions.h"
#include "mozilla/Atomics.h" #include "mozilla/Atomics.h"
@ -1268,9 +1269,8 @@ Maybe<nsTArray<uint8_t>> nsRFPService::GenerateKey(nsIChannel* aChannel) {
// Set the partitionKey using the top level URI to ensure that the key is // Set the partitionKey using the top level URI to ensure that the key is
// specific to the top level site. // specific to the top level site.
bool foreignByAncestorContext = bool foreignByAncestorContext =
false; // Bug 1876575 will change this to AntiTrackingUtils::IsThirdPartyChannel(aChannel) &&
// loadInfo->GetIsInThirdPartyContext() && loadInfo->GetIsThirdPartyContextToTopWindow();
// !loadInfo->GetIsThirdPartyContextToTopWindow();
attrs.SetPartitionKey(topLevelURI, foreignByAncestorContext); attrs.SetPartitionKey(topLevelURI, foreignByAncestorContext);
nsAutoCString oaSuffix; nsAutoCString oaSuffix;
@ -2050,7 +2050,7 @@ Maybe<RFPTarget> nsRFPService::GetOverriddenFingerprintingSettingsForChannel(
} }
// The channel is for the first-party load. // The channel is for the first-party load.
if (!loadInfo->GetIsThirdPartyContextToTopWindow()) { if (!AntiTrackingUtils::IsThirdPartyChannel(aChannel)) {
return GetOverriddenFingerprintingSettingsForURI(uri, nullptr); return GetOverriddenFingerprintingSettingsForURI(uri, nullptr);
} }