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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozIThirdPartyUtil.h"
#include "mozilla/AntiTrackingUtils.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Components.h"
#include "mozilla/ContentBlockingAllowList.h"
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/net/CookieJarSettings.h"
@ -539,10 +541,9 @@ void CookieJarSettings::SetPartitionKey(nsIURI* aURI,
void CookieJarSettings::UpdatePartitionKeyForDocumentLoadedByChannel(
nsIChannel* aChannel) {
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
bool thirdParty = AntiTrackingUtils::IsThirdPartyChannel(aChannel);
bool foreignByAncestorContext =
false; // Bug 1876575 will change this to
// loadInfo->GetIsInThirdPartyContext() &&
// !loadInfo->GetIsThirdPartyContextToTopWindow();
thirdParty && !loadInfo->GetIsThirdPartyContextToTopWindow();
StoragePrincipalHelper::UpdatePartitionKeyWithForeignAncestorBit(
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
// instead. By doing this, an the resource inherits the principal from
// 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();
if (NS_WARN_IF(!ssm)) {
return;
@ -851,10 +852,36 @@ void AntiTrackingUtils::ComputeIsThirdPartyToTopWindow(nsIChannel* aChannel) {
bool AntiTrackingUtils::IsThirdPartyChannel(nsIChannel* aChannel) {
MOZ_ASSERT(aChannel);
// We only care whether the channel is 3rd-party with respect to
// the top-level.
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
return loadInfo->GetIsThirdPartyContextToTopWindow();
// We have to handle blob URLs here because they always fail
// 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();
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 */
@ -907,19 +934,29 @@ bool AntiTrackingUtils::IsThirdPartyWindow(nsPIDOMWindowInner* aWindow,
/* static */
bool AntiTrackingUtils::IsThirdPartyDocument(Document* 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
// 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
// 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();
return bc ? IsThirdPartyContext(bc) : true;
}
// We only care whether the channel is 3rd-party with respect to
// the top-level.
nsCOMPtr<nsILoadInfo> loadInfo = aDocument->GetChannel()->LoadInfo();
return loadInfo->GetIsThirdPartyContextToTopWindow();
nsresult rv = tpuService->IsThirdPartyChannel(aDocument->GetChannel(),
nullptr, &thirdParty);
NS_ENSURE_SUCCESS(rv, true);
return thirdParty;
}
/* static */
@ -927,41 +964,47 @@ bool AntiTrackingUtils::IsThirdPartyContext(BrowsingContext* aBrowsingContext) {
MOZ_ASSERT(aBrowsingContext);
MOZ_ASSERT(aBrowsingContext->IsInProcess());
if (aBrowsingContext->IsTopContent()) {
return false;
}
// If the top browsing context is not in the same process, it's cross-origin.
if (!aBrowsingContext->Top()->IsInProcess()) {
return true;
}
// iframes with SANDBOX_ORIGIN are always third-party contexts
// because they are a unique origin
nsIDocShell* docShell = aBrowsingContext->GetDocShell();
if (!docShell) {
return true;
}
Document* doc = docShell->GetExtantDocument();
if (!doc) {
if (!doc || doc->GetSandboxFlags() & SANDBOXED_ORIGIN) {
return true;
}
nsIPrincipal* principal = doc->NodePrincipal();
nsIDocShell* topDocShell = aBrowsingContext->Top()->GetDocShell();
if (!topDocShell) {
return true;
BrowsingContext* traversingParent = aBrowsingContext->GetParent();
while (traversingParent) {
// If the parent browsing context is not in the same process, it's
// cross-origin.
if (!traversingParent->IsInProcess()) {
return true;
}
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;
parentBasePrin->IsThirdPartyPrincipal(principal, &isThirdParty);
if (isThirdParty) {
return true;
}
traversingParent = traversingParent->GetParent();
}
Document* topDoc = topDocShell->GetDocument();
if (!topDoc) {
return true;
}
nsIPrincipal* topPrincipal = topDoc->NodePrincipal();
auto* topBasePrin = BasePrincipal::Cast(topPrincipal);
bool isThirdParty = true;
topBasePrin->IsThirdPartyPrincipal(principal, &isThirdParty);
return isThirdParty;
return false;
}
/* static */
@ -1009,13 +1052,17 @@ void AntiTrackingUtils::UpdateAntiTrackingInfoForChannel(nsIChannel* aChannel) {
->MarkOverriddenFingerprintingSettingsAsSet();
#endif
nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
Unused << loadInfo->GetCookieJarSettings(getter_AddRefs(cookieJarSettings));
// For subdocuments, the channel's partition key is that of the parent
// document. This document may have a different partition key, particularly
// one without the same-site bit.
net::CookieJarSettings::Cast(cookieJarSettings)
->UpdatePartitionKeyForDocumentLoadedByChannel(aChannel);
ExtContentPolicyType contentType = loadInfo->GetExternalContentPolicyType();
if (contentType == ExtContentPolicy::TYPE_DOCUMENT ||
contentType == ExtContentPolicy::TYPE_SUBDOCUMENT) {
nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
Unused << loadInfo->GetCookieJarSettings(getter_AddRefs(cookieJarSettings));
// For subdocuments, the channel's partition key is that of the parent
// document. This document may have a different partition key, particularly
// one without the same-site bit.
net::CookieJarSettings::Cast(cookieJarSettings)
->UpdatePartitionKeyForDocumentLoadedByChannel(aChannel);
}
// We only update the IsOnContentBlockingAllowList flag and the partition key
// 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
// for channels other than http channels.
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
if (!httpChannel || loadInfo->GetExternalContentPolicyType() !=
ExtContentPolicy::TYPE_DOCUMENT) {
if (!httpChannel || contentType != ExtContentPolicy::TYPE_DOCUMENT) {
return;
}
// Update the IsOnContentBlockingAllowList flag in the CookieJarSettings
// if this is a top level loading. For sub-document loading, this flag
// would inherit from the parent.
nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
Unused << loadInfo->GetCookieJarSettings(getter_AddRefs(cookieJarSettings));
net::CookieJarSettings::Cast(cookieJarSettings)
->UpdateIsOnContentBlockingAllowList(aChannel);

View file

@ -475,7 +475,6 @@ StorageAccessAPIHelper::CompleteAllowAccessForOnParentProcess(
[aParentContext, aTopLevelWindowId, trackingOrigin, trackingPrincipal,
aCookieBehavior,
aReason](int aAllowMode) -> RefPtr<StorageAccessPermissionGrantPromise> {
MOZ_ASSERT(!aParentContext->IsInProcess());
// 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,
// we'll return to the content process we need to inform when this
@ -1060,12 +1059,7 @@ StorageAccessAPIHelper::CheckSameSiteCallingContextDecidesStorageAccessAPI(
}
}
nsIChannel* chan = aDocument->GetChannel();
if (!chan) {
return Some(false);
}
nsCOMPtr<nsILoadInfo> loadInfo = chan->LoadInfo();
if (loadInfo->GetIsThirdPartyContextToTopWindow()) {
if (AntiTrackingUtils::IsThirdPartyDocument(aDocument)) {
return Some(false);
}

View file

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

View file

@ -19,6 +19,7 @@
#include "MainThreadUtils.h"
#include "ScopedNSSTypes.h"
#include "mozilla/AntiTrackingUtils.h"
#include "mozilla/ArrayIterator.h"
#include "mozilla/Assertions.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
// specific to the top level site.
bool foreignByAncestorContext =
false; // Bug 1876575 will change this to
// loadInfo->GetIsInThirdPartyContext() &&
// !loadInfo->GetIsThirdPartyContextToTopWindow();
AntiTrackingUtils::IsThirdPartyChannel(aChannel) &&
loadInfo->GetIsThirdPartyContextToTopWindow();
attrs.SetPartitionKey(topLevelURI, foreignByAncestorContext);
nsAutoCString oaSuffix;
@ -2050,7 +2050,7 @@ Maybe<RFPTarget> nsRFPService::GetOverriddenFingerprintingSettingsForChannel(
}
// The channel is for the first-party load.
if (!loadInfo->GetIsThirdPartyContextToTopWindow()) {
if (!AntiTrackingUtils::IsThirdPartyChannel(aChannel)) {
return GetOverriddenFingerprintingSettingsForURI(uri, nullptr);
}