зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1765313, part 2 - Move the ShouldAllowAccessFor functions to StorageAccess.h, r=anti-tracking-reviewers,timhuang
These functions are used to check if an object or context should have storage access. Therefore they belong in StorageAccess.h with other functions that serve this purpose. Differential Revision: https://phabricator.services.mozilla.com/D148285
This commit is contained in:
Родитель
1290825926
Коммит
5157d54b3b
|
@ -36,7 +36,7 @@
|
|||
#include "prnetdb.h"
|
||||
#include "nsIURIFixup.h"
|
||||
#include "mozilla/dom/StorageUtils.h"
|
||||
#include "mozilla/ContentBlocking.h"
|
||||
#include "mozilla/StorageAccess.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsIURIMutator.h"
|
||||
#include "mozilla/PermissionManager.h"
|
||||
|
@ -785,8 +785,7 @@ BasePrincipal::HasFirstpartyStorageAccess(mozIDOMWindow* aCheckWindow,
|
|||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
*aOutAllowed =
|
||||
ContentBlocking::ShouldAllowAccessFor(win, uri, aRejectedReason);
|
||||
*aOutAllowed = ShouldAllowAccessFor(win, uri, aRejectedReason);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,6 @@
|
|||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "mozilla/CSSEnabledState.h"
|
||||
#include "mozilla/ContentBlocking.h"
|
||||
#include "mozilla/ContentBlockingAllowList.h"
|
||||
#include "mozilla/ContentBlockingNotifier.h"
|
||||
#include "mozilla/ContentBlockingUserInteraction.h"
|
||||
|
@ -17701,8 +17700,7 @@ nsIPrincipal* Document::EffectiveStoragePrincipal() const {
|
|||
// We use the lower-level ContentBlocking API here to ensure this
|
||||
// check doesn't send notifications.
|
||||
uint32_t rejectedReason = 0;
|
||||
if (ContentBlocking::ShouldAllowAccessFor(inner, GetDocumentURI(),
|
||||
&rejectedReason)) {
|
||||
if (ShouldAllowAccessFor(inner, GetDocumentURI(), &rejectedReason)) {
|
||||
return mActiveStoragePrincipal = NodePrincipal();
|
||||
}
|
||||
|
||||
|
|
|
@ -13,12 +13,12 @@
|
|||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/ContentBlocking.h"
|
||||
#include "mozilla/ContentBlockingNotifier.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/MacroForEach.h"
|
||||
#include "mozilla/Components.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/StorageAccess.h"
|
||||
#include "mozilla/TextUtils.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
|
@ -512,8 +512,8 @@ ThirdPartyUtil::AnalyzeChannel(nsIChannel* aChannel, bool aNotify, nsIURI* aURI,
|
|||
aRequireThirdPartyCheck ? result.contains(ThirdPartyAnalysis::IsForeign)
|
||||
: true;
|
||||
if (performStorageChecks &&
|
||||
ContentBlocking::ShouldAllowAccessFor(aChannel, aURI ? aURI : uri.get(),
|
||||
aRejectedReason)) {
|
||||
ShouldAllowAccessFor(aChannel, aURI ? aURI : uri.get(),
|
||||
aRejectedReason)) {
|
||||
result += ThirdPartyAnalysis::IsStorageAccessPermissionGranted;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,13 +20,13 @@
|
|||
#include "ReferrerInfo.h"
|
||||
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "mozilla/ContentBlocking.h"
|
||||
#include "mozilla/ContentBlockingAllowList.h"
|
||||
#include "mozilla/net/CookieJarSettings.h"
|
||||
#include "mozilla/net/HttpBaseChannel.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/StaticPrefs_network.h"
|
||||
#include "mozilla/StorageAccess.h"
|
||||
#include "mozilla/StyleSheet.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsIWebProgressListener.h"
|
||||
|
@ -210,8 +210,7 @@ ReferrerPolicy ReferrerInfo::GetDefaultReferrerPolicy(nsIHttpChannel* aChannel,
|
|||
if (XRE_IsParentProcess() && cjs->GetRejectThirdPartyContexts()) {
|
||||
uint32_t rejectedReason = 0;
|
||||
thirdPartyTrackerIsolated =
|
||||
!ContentBlocking::ShouldAllowAccessFor(aChannel, aURI,
|
||||
&rejectedReason) &&
|
||||
!ShouldAllowAccessFor(aChannel, aURI, &rejectedReason) &&
|
||||
rejectedReason !=
|
||||
static_cast<uint32_t>(
|
||||
nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN);
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include <utility>
|
||||
|
||||
#include "mozilla/AntiTrackingUtils.h"
|
||||
#include "mozilla/ContentBlocking.h"
|
||||
#include "mozilla/HashFunctions.h"
|
||||
#include "mozilla/StorageAccess.h"
|
||||
#include "mozilla/StoragePrincipalHelper.h"
|
||||
|
@ -17,6 +16,7 @@
|
|||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/ServiceWorkerManager.h"
|
||||
#include "mozilla/StaticPrefs_privacy.h"
|
||||
#include "mozilla/StorageAccess.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
|
@ -153,8 +153,8 @@ nsCString ImageCacheKey::GetIsolationKey(Document* aDocument, nsIURI* aURI) {
|
|||
// this point. The best approach here is to be conservative: if we are sure
|
||||
// that the permission is granted, let's return 0. Otherwise, let's make a
|
||||
// unique image cache per the top-level document eTLD+1.
|
||||
if (!ContentBlocking::ApproximateAllowAccessForWithoutChannel(
|
||||
aDocument->GetInnerWindow(), aURI)) {
|
||||
if (!ApproximateAllowAccessForWithoutChannel(aDocument->GetInnerWindow(),
|
||||
aURI)) {
|
||||
// If we are here, the image is a 3rd-party resource loaded by a first-party
|
||||
// context. We can just use the document's base domain as the key because it
|
||||
// should be the same as the top-level document's base domain.
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
#include "CookieCommons.h"
|
||||
#include "CookieLogging.h"
|
||||
#include "CookieService.h"
|
||||
#include "mozilla/ContentBlocking.h"
|
||||
#include "mozilla/ConsoleReportCollector.h"
|
||||
#include "mozilla/ContentBlockingNotifier.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/StaticPrefs_network.h"
|
||||
#include "mozilla/StorageAccess.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/nsMixedContentBlocker.h"
|
||||
#include "mozilla/net/CookieJarSettings.h"
|
||||
|
@ -386,8 +386,7 @@ already_AddRefed<Cookie> CookieCommons::CreateCookieFromDocument(
|
|||
if (aDocument->CookieJarSettings()->GetLimitForeignContexts() &&
|
||||
!aHasExistingCookiesLambda(baseDomain,
|
||||
storagePrincipal->OriginAttributesRef()) &&
|
||||
!ContentBlocking::ShouldAllowAccessFor(innerWindow, principalURI,
|
||||
&dummyRejectedReason)) {
|
||||
!ShouldAllowAccessFor(innerWindow, principalURI, &dummyRejectedReason)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
|
||||
#include "ClassifierDummyChannel.h"
|
||||
|
||||
#include "mozilla/ContentBlocking.h"
|
||||
#include "mozilla/net/ClassifierDummyChannelChild.h"
|
||||
#include "mozilla/net/UrlClassifierCommon.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/StaticPrefs_privacy.h"
|
||||
#include "mozilla/StorageAccess.h"
|
||||
#include "nsContentSecurityManager.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIURI.h"
|
||||
|
@ -64,7 +64,7 @@ ClassifierDummyChannel::StorageAllowed(
|
|||
return eAsyncNeeded;
|
||||
}
|
||||
|
||||
if (ContentBlocking::ShouldAllowAccessFor(httpChannel, uri, nullptr)) {
|
||||
if (ShouldAllowAccessFor(httpChannel, uri, nullptr)) {
|
||||
return eStorageGranted;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ClassifierDummyChannelChild.h"
|
||||
#include "mozilla/ContentBlocking.h"
|
||||
#include "mozilla/ipc/BackgroundUtils.h"
|
||||
#include "mozilla/ipc/URIUtils.h"
|
||||
#include "nsIURI.h"
|
||||
#include "mozilla/AntiTrackingUtils.h"
|
||||
#include "mozilla/StorageAccess.h"
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "mozilla/net/NeckoChannelParams.h"
|
||||
|
@ -82,8 +82,7 @@ mozilla::ipc::IPCResult ClassifierDummyChannelChild::Recv__delete__(
|
|||
RefPtr<HttpBaseChannel> httpChannel = do_QueryObject(channel);
|
||||
httpChannel->AddClassificationFlags(aClassificationFlags, mIsThirdParty);
|
||||
|
||||
bool storageGranted =
|
||||
ContentBlocking::ShouldAllowAccessFor(httpChannel, mURI, nullptr);
|
||||
bool storageGranted = ShouldAllowAccessFor(httpChannel, mURI, nullptr);
|
||||
mCallback(storageGranted);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
|
|
@ -1133,453 +1133,3 @@ void ContentBlocking::UpdateAllowAccessOnParentProcess(
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool ContentBlocking::ShouldAllowAccessFor(nsPIDOMWindowInner* aWindow,
|
||||
nsIURI* aURI,
|
||||
uint32_t* aRejectedReason) {
|
||||
MOZ_ASSERT(aWindow);
|
||||
MOZ_ASSERT(aURI);
|
||||
|
||||
// Let's avoid a null check on aRejectedReason everywhere else.
|
||||
uint32_t rejectedReason = 0;
|
||||
if (!aRejectedReason) {
|
||||
aRejectedReason = &rejectedReason;
|
||||
}
|
||||
|
||||
LOG_SPEC(("Computing whether window %p has access to URI %s", aWindow, _spec),
|
||||
aURI);
|
||||
|
||||
nsGlobalWindowInner* innerWindow = nsGlobalWindowInner::Cast(aWindow);
|
||||
Document* document = innerWindow->GetExtantDoc();
|
||||
if (!document) {
|
||||
LOG(("Our window has no document"));
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t cookiePermission = CheckCookiePermissionForPrincipal(
|
||||
document->CookieJarSettings(), document->NodePrincipal());
|
||||
if (cookiePermission != nsICookiePermission::ACCESS_DEFAULT) {
|
||||
LOG(
|
||||
("CheckCookiePermissionForPrincipal() returned a non-default access "
|
||||
"code (%d) for window's principal, returning %s",
|
||||
int(cookiePermission),
|
||||
cookiePermission != nsICookiePermission::ACCESS_DENY ? "success"
|
||||
: "failure"));
|
||||
if (cookiePermission != nsICookiePermission::ACCESS_DENY) {
|
||||
return true;
|
||||
}
|
||||
|
||||
*aRejectedReason =
|
||||
nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION;
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t behavior = CookiesBehavior(document);
|
||||
if (behavior == nsICookieService::BEHAVIOR_ACCEPT) {
|
||||
LOG(("The cookie behavior pref mandates accepting all cookies!"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ContentBlockingAllowList::Check(aWindow)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (behavior == nsICookieService::BEHAVIOR_REJECT) {
|
||||
LOG(("The cookie behavior pref mandates rejecting all cookies!"));
|
||||
*aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// As a performance optimization, we only perform this check for
|
||||
// BEHAVIOR_REJECT_FOREIGN and BEHAVIOR_LIMIT_FOREIGN. For
|
||||
// BEHAVIOR_REJECT_TRACKER and BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN,
|
||||
// third-partiness is implicily checked later below.
|
||||
if (behavior != nsICookieService::BEHAVIOR_REJECT_TRACKER &&
|
||||
behavior !=
|
||||
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) {
|
||||
// Let's check if this is a 3rd party context.
|
||||
if (!AntiTrackingUtils::IsThirdPartyWindow(aWindow, aURI)) {
|
||||
LOG(("Our window isn't a third-party window"));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN &&
|
||||
!CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior)) ||
|
||||
behavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) {
|
||||
// XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by
|
||||
// simply rejecting the request to use the storage. In the future, if we
|
||||
// change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense
|
||||
// for non-cookie storage types, this may change.
|
||||
LOG(("Nothing more to do due to the behavior code %d", int(behavior)));
|
||||
*aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN;
|
||||
return false;
|
||||
}
|
||||
|
||||
// The document has been allowlisted. We can return from here directly.
|
||||
if (document->HasStorageAccessPermissionGrantedByAllowList()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(
|
||||
CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior) ||
|
||||
behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER ||
|
||||
behavior ==
|
||||
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN);
|
||||
|
||||
uint32_t blockedReason =
|
||||
nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER;
|
||||
|
||||
if (behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER) {
|
||||
if (!nsContentUtils::IsThirdPartyTrackingResourceWindow(aWindow)) {
|
||||
LOG(("Our window isn't a third-party tracking window"));
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIClassifiedChannel> classifiedChannel =
|
||||
do_QueryInterface(document->GetChannel());
|
||||
if (classifiedChannel) {
|
||||
uint32_t classificationFlags =
|
||||
classifiedChannel->GetThirdPartyClassificationFlags();
|
||||
if (classificationFlags & nsIClassifiedChannel::ClassificationFlags::
|
||||
CLASSIFIED_SOCIALTRACKING) {
|
||||
blockedReason =
|
||||
nsIWebProgressListener::STATE_COOKIES_BLOCKED_SOCIALTRACKER;
|
||||
}
|
||||
}
|
||||
} else if (behavior ==
|
||||
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) {
|
||||
if (nsContentUtils::IsThirdPartyTrackingResourceWindow(aWindow)) {
|
||||
// fall through
|
||||
} else if (AntiTrackingUtils::IsThirdPartyWindow(aWindow, aURI)) {
|
||||
LOG(("We're in the third-party context, storage should be partitioned"));
|
||||
// fall through, but remember that we're partitioning.
|
||||
blockedReason = nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN;
|
||||
} else {
|
||||
LOG(("Our window isn't a third-party window, storage is allowed"));
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior));
|
||||
if (RejectForeignAllowList::Check(document)) {
|
||||
LOG(("This window is exceptionlisted for reject foreign"));
|
||||
return true;
|
||||
}
|
||||
|
||||
blockedReason = nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN;
|
||||
}
|
||||
|
||||
Document* doc = aWindow->GetExtantDoc();
|
||||
// Make sure storage access isn't disabled
|
||||
if (doc && (doc->StorageAccessSandboxed())) {
|
||||
LOG(("Our document is sandboxed"));
|
||||
*aRejectedReason = blockedReason;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Document::HasStoragePermission first checks if storage access granted is
|
||||
// cached in the inner window, if no, it then checks the storage permission
|
||||
// flag in the channel's loadinfo
|
||||
bool allowed = document->HasStorageAccessPermissionGranted();
|
||||
|
||||
if (!allowed) {
|
||||
*aRejectedReason = blockedReason;
|
||||
} else {
|
||||
if (MOZ_LOG_TEST(gAntiTrackingLog, mozilla::LogLevel::Debug) &&
|
||||
aWindow->HasStorageAccessPermissionGranted()) {
|
||||
LOG(("Permission stored in the window. All good."));
|
||||
}
|
||||
}
|
||||
|
||||
return allowed;
|
||||
}
|
||||
|
||||
bool ContentBlocking::ShouldAllowAccessFor(nsIChannel* aChannel, nsIURI* aURI,
|
||||
uint32_t* aRejectedReason) {
|
||||
MOZ_ASSERT(aURI);
|
||||
MOZ_ASSERT(aChannel);
|
||||
|
||||
// Let's avoid a null check on aRejectedReason everywhere else.
|
||||
uint32_t rejectedReason = 0;
|
||||
if (!aRejectedReason) {
|
||||
aRejectedReason = &rejectedReason;
|
||||
}
|
||||
|
||||
nsIScriptSecurityManager* ssm =
|
||||
nsScriptSecurityManager::GetScriptSecurityManager();
|
||||
MOZ_ASSERT(ssm);
|
||||
|
||||
nsCOMPtr<nsIURI> channelURI;
|
||||
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI));
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("Failed to get the channel final URI, bail out early"));
|
||||
return true;
|
||||
}
|
||||
LOG_SPEC(
|
||||
("Computing whether channel %p has access to URI %s", aChannel, _spec),
|
||||
channelURI);
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
|
||||
nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
|
||||
rv = loadInfo->GetCookieJarSettings(getter_AddRefs(cookieJarSettings));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
LOG(
|
||||
("Failed to get the cookie jar settings from the loadinfo, bail out "
|
||||
"early"));
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> channelPrincipal;
|
||||
rv = ssm->GetChannelURIPrincipal(aChannel, getter_AddRefs(channelPrincipal));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
LOG(("No channel principal, bail out early"));
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t cookiePermission =
|
||||
CheckCookiePermissionForPrincipal(cookieJarSettings, channelPrincipal);
|
||||
if (cookiePermission != nsICookiePermission::ACCESS_DEFAULT) {
|
||||
LOG(
|
||||
("CheckCookiePermissionForPrincipal() returned a non-default access "
|
||||
"code (%d) for channel's principal, returning %s",
|
||||
int(cookiePermission),
|
||||
cookiePermission != nsICookiePermission::ACCESS_DENY ? "success"
|
||||
: "failure"));
|
||||
if (cookiePermission != nsICookiePermission::ACCESS_DENY) {
|
||||
return true;
|
||||
}
|
||||
|
||||
*aRejectedReason =
|
||||
nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!channelURI) {
|
||||
LOG(("No channel uri, bail out early"));
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t behavior = CookiesBehavior(loadInfo, channelURI);
|
||||
if (behavior == nsICookieService::BEHAVIOR_ACCEPT) {
|
||||
LOG(("The cookie behavior pref mandates accepting all cookies!"));
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
|
||||
|
||||
if (httpChannel && ContentBlockingAllowList::Check(httpChannel)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (behavior == nsICookieService::BEHAVIOR_REJECT) {
|
||||
LOG(("The cookie behavior pref mandates rejecting all cookies!"));
|
||||
*aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL;
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
|
||||
components::ThirdPartyUtil::Service();
|
||||
if (!thirdPartyUtil) {
|
||||
LOG(("No thirdPartyUtil, bail out early"));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool thirdParty = false;
|
||||
rv = thirdPartyUtil->IsThirdPartyChannel(aChannel, aURI, &thirdParty);
|
||||
// Grant if it's not a 3rd party.
|
||||
// Be careful to check the return value of IsThirdPartyChannel, since
|
||||
// IsThirdPartyChannel() will fail if the channel's loading principal is the
|
||||
// system principal...
|
||||
if (NS_SUCCEEDED(rv) && !thirdParty) {
|
||||
LOG(("Our channel isn't a third-party channel"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN &&
|
||||
!CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior)) ||
|
||||
behavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) {
|
||||
// XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by
|
||||
// simply rejecting the request to use the storage. In the future, if we
|
||||
// change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense
|
||||
// for non-cookie storage types, this may change.
|
||||
LOG(("Nothing more to do due to the behavior code %d", int(behavior)));
|
||||
*aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN;
|
||||
return false;
|
||||
}
|
||||
|
||||
// The channel has been allowlisted. We can return from here.
|
||||
if (loadInfo->GetStoragePermission() ==
|
||||
nsILoadInfo::StoragePermissionAllowListed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(
|
||||
CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior) ||
|
||||
behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER ||
|
||||
behavior ==
|
||||
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN);
|
||||
|
||||
uint32_t blockedReason =
|
||||
nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER;
|
||||
|
||||
// Not a tracker.
|
||||
nsCOMPtr<nsIClassifiedChannel> classifiedChannel =
|
||||
do_QueryInterface(aChannel);
|
||||
if (behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER) {
|
||||
if (classifiedChannel) {
|
||||
if (!classifiedChannel->IsThirdPartyTrackingResource()) {
|
||||
LOG(("Our channel isn't a third-party tracking channel"));
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t classificationFlags =
|
||||
classifiedChannel->GetThirdPartyClassificationFlags();
|
||||
if (classificationFlags & nsIClassifiedChannel::ClassificationFlags::
|
||||
CLASSIFIED_SOCIALTRACKING) {
|
||||
blockedReason =
|
||||
nsIWebProgressListener::STATE_COOKIES_BLOCKED_SOCIALTRACKER;
|
||||
}
|
||||
}
|
||||
} else if (behavior ==
|
||||
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) {
|
||||
if (classifiedChannel &&
|
||||
classifiedChannel->IsThirdPartyTrackingResource()) {
|
||||
// fall through
|
||||
} else if (AntiTrackingUtils::IsThirdPartyChannel(aChannel)) {
|
||||
LOG(("We're in the third-party context, storage should be partitioned"));
|
||||
// fall through but remember that we're partitioning.
|
||||
blockedReason = nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN;
|
||||
} else {
|
||||
LOG(("Our channel isn't a third-party channel, storage is allowed"));
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior));
|
||||
if (httpChannel && RejectForeignAllowList::Check(httpChannel)) {
|
||||
LOG(("This channel is exceptionlisted"));
|
||||
return true;
|
||||
}
|
||||
blockedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN;
|
||||
}
|
||||
|
||||
RefPtr<BrowsingContext> targetBC;
|
||||
rv = loadInfo->GetTargetBrowsingContext(getter_AddRefs(targetBC));
|
||||
if (!targetBC || NS_WARN_IF(NS_FAILED(rv))) {
|
||||
LOG(("Failed to get the channel's target browsing context"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Document::StorageAccessSandboxed(targetBC->GetSandboxFlags())) {
|
||||
LOG(("Our document is sandboxed"));
|
||||
*aRejectedReason = blockedReason;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Let's see if we have to grant the access for this particular channel.
|
||||
|
||||
// HasStorageAccessPermissionGranted only applies to channels that load
|
||||
// documents, for sub-resources loads, just returns the result from loadInfo.
|
||||
bool isDocument = false;
|
||||
aChannel->GetIsDocument(&isDocument);
|
||||
|
||||
if (isDocument) {
|
||||
nsCOMPtr<nsPIDOMWindowInner> inner =
|
||||
AntiTrackingUtils::GetInnerWindow(targetBC);
|
||||
if (inner && inner->HasStorageAccessPermissionGranted()) {
|
||||
LOG(("Permission stored in the window. All good."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool allowed =
|
||||
loadInfo->GetStoragePermission() != nsILoadInfo::NoStoragePermission;
|
||||
if (!allowed) {
|
||||
*aRejectedReason = blockedReason;
|
||||
}
|
||||
|
||||
return allowed;
|
||||
}
|
||||
|
||||
bool ContentBlocking::ShouldAllowAccessFor(
|
||||
nsIPrincipal* aPrincipal, nsICookieJarSettings* aCookieJarSettings) {
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
MOZ_ASSERT(aCookieJarSettings);
|
||||
|
||||
uint32_t access = nsICookiePermission::ACCESS_DEFAULT;
|
||||
if (aPrincipal->GetIsContentPrincipal()) {
|
||||
PermissionManager* permManager = PermissionManager::GetInstance();
|
||||
if (permManager) {
|
||||
Unused << NS_WARN_IF(NS_FAILED(permManager->TestPermissionFromPrincipal(
|
||||
aPrincipal, "cookie"_ns, &access)));
|
||||
}
|
||||
}
|
||||
|
||||
if (access != nsICookiePermission::ACCESS_DEFAULT) {
|
||||
return access != nsICookiePermission::ACCESS_DENY;
|
||||
}
|
||||
|
||||
int32_t behavior = CookiesBehavior(aPrincipal, aCookieJarSettings);
|
||||
return behavior != nsICookieService::BEHAVIOR_REJECT;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool ContentBlocking::ApproximateAllowAccessForWithoutChannel(
|
||||
nsPIDOMWindowInner* aFirstPartyWindow, nsIURI* aURI) {
|
||||
MOZ_ASSERT(aFirstPartyWindow);
|
||||
MOZ_ASSERT(aURI);
|
||||
|
||||
LOG_SPEC(
|
||||
("Computing a best guess as to whether window %p has access to URI %s",
|
||||
aFirstPartyWindow, _spec),
|
||||
aURI);
|
||||
|
||||
Document* parentDocument =
|
||||
nsGlobalWindowInner::Cast(aFirstPartyWindow)->GetExtantDoc();
|
||||
if (NS_WARN_IF(!parentDocument)) {
|
||||
LOG(("Failed to get the first party window's document"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parentDocument->CookieJarSettings()->GetRejectThirdPartyContexts()) {
|
||||
LOG(("Disabled by the pref (%d), bail out early",
|
||||
parentDocument->CookieJarSettings()->GetCookieBehavior()));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ContentBlockingAllowList::Check(aFirstPartyWindow)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!AntiTrackingUtils::IsThirdPartyWindow(aFirstPartyWindow, aURI)) {
|
||||
LOG(("Our window isn't a third-party window"));
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t cookiePermission = CheckCookiePermissionForPrincipal(
|
||||
parentDocument->CookieJarSettings(), parentDocument->NodePrincipal());
|
||||
if (cookiePermission != nsICookiePermission::ACCESS_DEFAULT) {
|
||||
LOG(
|
||||
("CheckCookiePermissionForPrincipal() returned a non-default access "
|
||||
"code (%d), returning %s",
|
||||
int(cookiePermission),
|
||||
cookiePermission != nsICookiePermission::ACCESS_DENY ? "success"
|
||||
: "failure"));
|
||||
return cookiePermission != nsICookiePermission::ACCESS_DENY;
|
||||
}
|
||||
|
||||
nsAutoCString origin;
|
||||
nsresult rv = nsContentUtils::GetASCIIOrigin(aURI, origin);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
LOG_SPEC(("Failed to compute the origin from %s", _spec), aURI);
|
||||
return false;
|
||||
}
|
||||
|
||||
nsIPrincipal* parentPrincipal = parentDocument->NodePrincipal();
|
||||
|
||||
nsAutoCString type;
|
||||
AntiTrackingUtils::CreateStoragePermissionKey(origin, type);
|
||||
|
||||
return AntiTrackingUtils::CheckStoragePermission(
|
||||
parentPrincipal, type,
|
||||
nsContentUtils::IsInPrivateBrowsing(parentDocument), nullptr, 0);
|
||||
}
|
||||
|
|
|
@ -35,42 +35,6 @@ class Document;
|
|||
|
||||
class ContentBlocking final {
|
||||
public:
|
||||
// This method returns true if the URI has first party storage access when
|
||||
// loaded inside the passed 3rd party context tracking resource window.
|
||||
// If the window is first party context, please use
|
||||
// ApproximateAllowAccessForWithoutChannel();
|
||||
//
|
||||
// aRejectedReason could be set to one of these values if passed and if the
|
||||
// storage permission is not granted:
|
||||
// * nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION
|
||||
// * nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER
|
||||
// * nsIWebProgressListener::STATE_COOKIES_BLOCKED_SOCIALTRACKER
|
||||
// * nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL
|
||||
// * nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN
|
||||
static bool ShouldAllowAccessFor(nsPIDOMWindowInner* a3rdPartyTrackingWindow,
|
||||
nsIURI* aURI, uint32_t* aRejectedReason);
|
||||
|
||||
// Note: you should use ShouldAllowAccessFor() passing the nsIChannel! Use
|
||||
// this method _only_ if the channel is not available. For first party
|
||||
// window, it's impossible to know if the aURI is a tracking resource
|
||||
// synchronously, so here we return the best guest: if we are sure that the
|
||||
// permission is granted for the origin of aURI, this method returns true,
|
||||
// otherwise false.
|
||||
static bool ApproximateAllowAccessForWithoutChannel(
|
||||
nsPIDOMWindowInner* aFirstPartyWindow, nsIURI* aURI);
|
||||
|
||||
// It returns true if the URI has access to the first party storage.
|
||||
// aChannel can be a 3rd party channel, or not.
|
||||
// See ShouldAllowAccessFor(window) to see the possible values of
|
||||
// aRejectedReason.
|
||||
static bool ShouldAllowAccessFor(nsIChannel* aChannel, nsIURI* aURI,
|
||||
uint32_t* aRejectedReason);
|
||||
|
||||
// This method checks if the principal has the permission to access to the
|
||||
// first party storage.
|
||||
static bool ShouldAllowAccessFor(nsIPrincipal* aPrincipal,
|
||||
nsICookieJarSettings* aCookieJarSettings);
|
||||
|
||||
enum StorageAccessPromptChoices { eAllow, eAllowAutoGrant };
|
||||
|
||||
// Grant the permission for aOrigin to have access to the first party storage.
|
||||
|
|
|
@ -30,6 +30,7 @@ class ContentBlockingAllowList final {
|
|||
bool aIsPrivateBrowsing, bool& aIsAllowListed);
|
||||
|
||||
static bool Check(nsIHttpChannel* aChannel);
|
||||
static bool Check(nsPIDOMWindowInner* aWindow);
|
||||
|
||||
// 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
|
||||
|
@ -44,7 +45,6 @@ class ContentBlockingAllowList final {
|
|||
private:
|
||||
// Utility APIs for ContentBlocking.
|
||||
static bool Check(nsIPrincipal* aTopWinPrincipal, bool aIsPrivateBrowsing);
|
||||
static bool Check(nsPIDOMWindowInner* aWindow);
|
||||
static bool Check(nsICookieJarSettings* aCookieJarSettings);
|
||||
|
||||
friend class ContentBlocking;
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/net/CookieJarSettings.h"
|
||||
#include "mozilla/ContentBlocking.h"
|
||||
#include "mozilla/StaticPrefs_browser.h"
|
||||
#include "mozilla/StaticPrefs_network.h"
|
||||
#include "mozilla/StaticPrefs_privacy.h"
|
||||
|
@ -227,8 +226,8 @@ static bool StorageDisabledByAntiTrackingInternal(
|
|||
|
||||
if (aWindow) {
|
||||
nsIURI* documentURI = aURI ? aURI : aWindow->GetDocumentURI();
|
||||
return !documentURI || !ContentBlocking::ShouldAllowAccessFor(
|
||||
aWindow, documentURI, &aRejectedReason);
|
||||
return !documentURI ||
|
||||
!ShouldAllowAccessFor(aWindow, documentURI, &aRejectedReason);
|
||||
}
|
||||
|
||||
if (aChannel) {
|
||||
|
@ -238,12 +237,11 @@ static bool StorageDisabledByAntiTrackingInternal(
|
|||
return false;
|
||||
}
|
||||
|
||||
return !ContentBlocking::ShouldAllowAccessFor(aChannel, uri,
|
||||
&aRejectedReason);
|
||||
return !ShouldAllowAccessFor(aChannel, uri, &aRejectedReason);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
return !ContentBlocking::ShouldAllowAccessFor(aPrincipal, aCookieJarSettings);
|
||||
return !ShouldAllowAccessFor(aPrincipal, aCookieJarSettings);
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -417,4 +415,453 @@ bool StoragePartitioningEnabled(uint32_t aRejectedReason,
|
|||
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN;
|
||||
}
|
||||
|
||||
bool ShouldAllowAccessFor(nsPIDOMWindowInner* aWindow, nsIURI* aURI,
|
||||
uint32_t* aRejectedReason) {
|
||||
MOZ_ASSERT(aWindow);
|
||||
MOZ_ASSERT(aURI);
|
||||
|
||||
// Let's avoid a null check on aRejectedReason everywhere else.
|
||||
uint32_t rejectedReason = 0;
|
||||
if (!aRejectedReason) {
|
||||
aRejectedReason = &rejectedReason;
|
||||
}
|
||||
|
||||
LOG_SPEC(("Computing whether window %p has access to URI %s", aWindow, _spec),
|
||||
aURI);
|
||||
|
||||
nsGlobalWindowInner* innerWindow = nsGlobalWindowInner::Cast(aWindow);
|
||||
Document* document = innerWindow->GetExtantDoc();
|
||||
if (!document) {
|
||||
LOG(("Our window has no document"));
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t cookiePermission = CheckCookiePermissionForPrincipal(
|
||||
document->CookieJarSettings(), document->NodePrincipal());
|
||||
if (cookiePermission != nsICookiePermission::ACCESS_DEFAULT) {
|
||||
LOG(
|
||||
("CheckCookiePermissionForPrincipal() returned a non-default access "
|
||||
"code (%d) for window's principal, returning %s",
|
||||
int(cookiePermission),
|
||||
cookiePermission != nsICookiePermission::ACCESS_DENY ? "success"
|
||||
: "failure"));
|
||||
if (cookiePermission != nsICookiePermission::ACCESS_DENY) {
|
||||
return true;
|
||||
}
|
||||
|
||||
*aRejectedReason =
|
||||
nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION;
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t behavior = CookiesBehavior(document);
|
||||
if (behavior == nsICookieService::BEHAVIOR_ACCEPT) {
|
||||
LOG(("The cookie behavior pref mandates accepting all cookies!"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ContentBlockingAllowList::Check(aWindow)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (behavior == nsICookieService::BEHAVIOR_REJECT) {
|
||||
LOG(("The cookie behavior pref mandates rejecting all cookies!"));
|
||||
*aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// As a performance optimization, we only perform this check for
|
||||
// BEHAVIOR_REJECT_FOREIGN and BEHAVIOR_LIMIT_FOREIGN. For
|
||||
// BEHAVIOR_REJECT_TRACKER and BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN,
|
||||
// third-partiness is implicily checked later below.
|
||||
if (behavior != nsICookieService::BEHAVIOR_REJECT_TRACKER &&
|
||||
behavior !=
|
||||
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) {
|
||||
// Let's check if this is a 3rd party context.
|
||||
if (!AntiTrackingUtils::IsThirdPartyWindow(aWindow, aURI)) {
|
||||
LOG(("Our window isn't a third-party window"));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN &&
|
||||
!CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior)) ||
|
||||
behavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) {
|
||||
// XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by
|
||||
// simply rejecting the request to use the storage. In the future, if we
|
||||
// change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense
|
||||
// for non-cookie storage types, this may change.
|
||||
LOG(("Nothing more to do due to the behavior code %d", int(behavior)));
|
||||
*aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN;
|
||||
return false;
|
||||
}
|
||||
|
||||
// The document has been allowlisted. We can return from here directly.
|
||||
if (document->HasStorageAccessPermissionGrantedByAllowList()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(
|
||||
CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior) ||
|
||||
behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER ||
|
||||
behavior ==
|
||||
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN);
|
||||
|
||||
uint32_t blockedReason =
|
||||
nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER;
|
||||
|
||||
if (behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER) {
|
||||
if (!nsContentUtils::IsThirdPartyTrackingResourceWindow(aWindow)) {
|
||||
LOG(("Our window isn't a third-party tracking window"));
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIClassifiedChannel> classifiedChannel =
|
||||
do_QueryInterface(document->GetChannel());
|
||||
if (classifiedChannel) {
|
||||
uint32_t classificationFlags =
|
||||
classifiedChannel->GetThirdPartyClassificationFlags();
|
||||
if (classificationFlags & nsIClassifiedChannel::ClassificationFlags::
|
||||
CLASSIFIED_SOCIALTRACKING) {
|
||||
blockedReason =
|
||||
nsIWebProgressListener::STATE_COOKIES_BLOCKED_SOCIALTRACKER;
|
||||
}
|
||||
}
|
||||
} else if (behavior ==
|
||||
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) {
|
||||
if (nsContentUtils::IsThirdPartyTrackingResourceWindow(aWindow)) {
|
||||
// fall through
|
||||
} else if (AntiTrackingUtils::IsThirdPartyWindow(aWindow, aURI)) {
|
||||
LOG(("We're in the third-party context, storage should be partitioned"));
|
||||
// fall through, but remember that we're partitioning.
|
||||
blockedReason = nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN;
|
||||
} else {
|
||||
LOG(("Our window isn't a third-party window, storage is allowed"));
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior));
|
||||
if (RejectForeignAllowList::Check(document)) {
|
||||
LOG(("This window is exceptionlisted for reject foreign"));
|
||||
return true;
|
||||
}
|
||||
|
||||
blockedReason = nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN;
|
||||
}
|
||||
|
||||
Document* doc = aWindow->GetExtantDoc();
|
||||
// Make sure storage access isn't disabled
|
||||
if (doc && (doc->StorageAccessSandboxed())) {
|
||||
LOG(("Our document is sandboxed"));
|
||||
*aRejectedReason = blockedReason;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Document::HasStoragePermission first checks if storage access granted is
|
||||
// cached in the inner window, if no, it then checks the storage permission
|
||||
// flag in the channel's loadinfo
|
||||
bool allowed = document->HasStorageAccessPermissionGranted();
|
||||
|
||||
if (!allowed) {
|
||||
*aRejectedReason = blockedReason;
|
||||
} else {
|
||||
if (MOZ_LOG_TEST(gAntiTrackingLog, mozilla::LogLevel::Debug) &&
|
||||
aWindow->HasStorageAccessPermissionGranted()) {
|
||||
LOG(("Permission stored in the window. All good."));
|
||||
}
|
||||
}
|
||||
|
||||
return allowed;
|
||||
}
|
||||
|
||||
bool ShouldAllowAccessFor(nsIChannel* aChannel, nsIURI* aURI,
|
||||
uint32_t* aRejectedReason) {
|
||||
MOZ_ASSERT(aURI);
|
||||
MOZ_ASSERT(aChannel);
|
||||
|
||||
// Let's avoid a null check on aRejectedReason everywhere else.
|
||||
uint32_t rejectedReason = 0;
|
||||
if (!aRejectedReason) {
|
||||
aRejectedReason = &rejectedReason;
|
||||
}
|
||||
|
||||
nsIScriptSecurityManager* ssm =
|
||||
nsScriptSecurityManager::GetScriptSecurityManager();
|
||||
MOZ_ASSERT(ssm);
|
||||
|
||||
nsCOMPtr<nsIURI> channelURI;
|
||||
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI));
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("Failed to get the channel final URI, bail out early"));
|
||||
return true;
|
||||
}
|
||||
LOG_SPEC(
|
||||
("Computing whether channel %p has access to URI %s", aChannel, _spec),
|
||||
channelURI);
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
|
||||
nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
|
||||
rv = loadInfo->GetCookieJarSettings(getter_AddRefs(cookieJarSettings));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
LOG(
|
||||
("Failed to get the cookie jar settings from the loadinfo, bail out "
|
||||
"early"));
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> channelPrincipal;
|
||||
rv = ssm->GetChannelURIPrincipal(aChannel, getter_AddRefs(channelPrincipal));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
LOG(("No channel principal, bail out early"));
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t cookiePermission =
|
||||
CheckCookiePermissionForPrincipal(cookieJarSettings, channelPrincipal);
|
||||
if (cookiePermission != nsICookiePermission::ACCESS_DEFAULT) {
|
||||
LOG(
|
||||
("CheckCookiePermissionForPrincipal() returned a non-default access "
|
||||
"code (%d) for channel's principal, returning %s",
|
||||
int(cookiePermission),
|
||||
cookiePermission != nsICookiePermission::ACCESS_DENY ? "success"
|
||||
: "failure"));
|
||||
if (cookiePermission != nsICookiePermission::ACCESS_DENY) {
|
||||
return true;
|
||||
}
|
||||
|
||||
*aRejectedReason =
|
||||
nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!channelURI) {
|
||||
LOG(("No channel uri, bail out early"));
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t behavior = CookiesBehavior(loadInfo, channelURI);
|
||||
if (behavior == nsICookieService::BEHAVIOR_ACCEPT) {
|
||||
LOG(("The cookie behavior pref mandates accepting all cookies!"));
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
|
||||
|
||||
if (httpChannel && ContentBlockingAllowList::Check(httpChannel)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (behavior == nsICookieService::BEHAVIOR_REJECT) {
|
||||
LOG(("The cookie behavior pref mandates rejecting all cookies!"));
|
||||
*aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL;
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
|
||||
components::ThirdPartyUtil::Service();
|
||||
if (!thirdPartyUtil) {
|
||||
LOG(("No thirdPartyUtil, bail out early"));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool thirdParty = false;
|
||||
rv = thirdPartyUtil->IsThirdPartyChannel(aChannel, aURI, &thirdParty);
|
||||
// Grant if it's not a 3rd party.
|
||||
// Be careful to check the return value of IsThirdPartyChannel, since
|
||||
// IsThirdPartyChannel() will fail if the channel's loading principal is the
|
||||
// system principal...
|
||||
if (NS_SUCCEEDED(rv) && !thirdParty) {
|
||||
LOG(("Our channel isn't a third-party channel"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN &&
|
||||
!CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior)) ||
|
||||
behavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) {
|
||||
// XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by
|
||||
// simply rejecting the request to use the storage. In the future, if we
|
||||
// change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense
|
||||
// for non-cookie storage types, this may change.
|
||||
LOG(("Nothing more to do due to the behavior code %d", int(behavior)));
|
||||
*aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN;
|
||||
return false;
|
||||
}
|
||||
|
||||
// The channel has been allowlisted. We can return from here.
|
||||
if (loadInfo->GetStoragePermission() ==
|
||||
nsILoadInfo::StoragePermissionAllowListed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(
|
||||
CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior) ||
|
||||
behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER ||
|
||||
behavior ==
|
||||
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN);
|
||||
|
||||
uint32_t blockedReason =
|
||||
nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER;
|
||||
|
||||
// Not a tracker.
|
||||
nsCOMPtr<nsIClassifiedChannel> classifiedChannel =
|
||||
do_QueryInterface(aChannel);
|
||||
if (behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER) {
|
||||
if (classifiedChannel) {
|
||||
if (!classifiedChannel->IsThirdPartyTrackingResource()) {
|
||||
LOG(("Our channel isn't a third-party tracking channel"));
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t classificationFlags =
|
||||
classifiedChannel->GetThirdPartyClassificationFlags();
|
||||
if (classificationFlags & nsIClassifiedChannel::ClassificationFlags::
|
||||
CLASSIFIED_SOCIALTRACKING) {
|
||||
blockedReason =
|
||||
nsIWebProgressListener::STATE_COOKIES_BLOCKED_SOCIALTRACKER;
|
||||
}
|
||||
}
|
||||
} else if (behavior ==
|
||||
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) {
|
||||
if (classifiedChannel &&
|
||||
classifiedChannel->IsThirdPartyTrackingResource()) {
|
||||
// fall through
|
||||
} else if (AntiTrackingUtils::IsThirdPartyChannel(aChannel)) {
|
||||
LOG(("We're in the third-party context, storage should be partitioned"));
|
||||
// fall through but remember that we're partitioning.
|
||||
blockedReason = nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN;
|
||||
} else {
|
||||
LOG(("Our channel isn't a third-party channel, storage is allowed"));
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior));
|
||||
if (httpChannel && RejectForeignAllowList::Check(httpChannel)) {
|
||||
LOG(("This channel is exceptionlisted"));
|
||||
return true;
|
||||
}
|
||||
blockedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN;
|
||||
}
|
||||
|
||||
RefPtr<BrowsingContext> targetBC;
|
||||
rv = loadInfo->GetTargetBrowsingContext(getter_AddRefs(targetBC));
|
||||
if (!targetBC || NS_WARN_IF(NS_FAILED(rv))) {
|
||||
LOG(("Failed to get the channel's target browsing context"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Document::StorageAccessSandboxed(targetBC->GetSandboxFlags())) {
|
||||
LOG(("Our document is sandboxed"));
|
||||
*aRejectedReason = blockedReason;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Let's see if we have to grant the access for this particular channel.
|
||||
|
||||
// HasStorageAccessPermissionGranted only applies to channels that load
|
||||
// documents, for sub-resources loads, just returns the result from loadInfo.
|
||||
bool isDocument = false;
|
||||
aChannel->GetIsDocument(&isDocument);
|
||||
|
||||
if (isDocument) {
|
||||
nsCOMPtr<nsPIDOMWindowInner> inner =
|
||||
AntiTrackingUtils::GetInnerWindow(targetBC);
|
||||
if (inner && inner->HasStorageAccessPermissionGranted()) {
|
||||
LOG(("Permission stored in the window. All good."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool allowed =
|
||||
loadInfo->GetStoragePermission() != nsILoadInfo::NoStoragePermission;
|
||||
if (!allowed) {
|
||||
*aRejectedReason = blockedReason;
|
||||
}
|
||||
|
||||
return allowed;
|
||||
}
|
||||
|
||||
bool ShouldAllowAccessFor(nsIPrincipal* aPrincipal,
|
||||
nsICookieJarSettings* aCookieJarSettings) {
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
MOZ_ASSERT(aCookieJarSettings);
|
||||
|
||||
uint32_t access = nsICookiePermission::ACCESS_DEFAULT;
|
||||
if (aPrincipal->GetIsContentPrincipal()) {
|
||||
PermissionManager* permManager = PermissionManager::GetInstance();
|
||||
if (permManager) {
|
||||
Unused << NS_WARN_IF(NS_FAILED(permManager->TestPermissionFromPrincipal(
|
||||
aPrincipal, "cookie"_ns, &access)));
|
||||
}
|
||||
}
|
||||
|
||||
if (access != nsICookiePermission::ACCESS_DEFAULT) {
|
||||
return access != nsICookiePermission::ACCESS_DENY;
|
||||
}
|
||||
|
||||
int32_t behavior = CookiesBehavior(aPrincipal, aCookieJarSettings);
|
||||
return behavior != nsICookieService::BEHAVIOR_REJECT;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool ApproximateAllowAccessForWithoutChannel(
|
||||
nsPIDOMWindowInner* aFirstPartyWindow, nsIURI* aURI) {
|
||||
MOZ_ASSERT(aFirstPartyWindow);
|
||||
MOZ_ASSERT(aURI);
|
||||
|
||||
LOG_SPEC(
|
||||
("Computing a best guess as to whether window %p has access to URI %s",
|
||||
aFirstPartyWindow, _spec),
|
||||
aURI);
|
||||
|
||||
Document* parentDocument =
|
||||
nsGlobalWindowInner::Cast(aFirstPartyWindow)->GetExtantDoc();
|
||||
if (NS_WARN_IF(!parentDocument)) {
|
||||
LOG(("Failed to get the first party window's document"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parentDocument->CookieJarSettings()->GetRejectThirdPartyContexts()) {
|
||||
LOG(("Disabled by the pref (%d), bail out early",
|
||||
parentDocument->CookieJarSettings()->GetCookieBehavior()));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ContentBlockingAllowList::Check(aFirstPartyWindow)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!AntiTrackingUtils::IsThirdPartyWindow(aFirstPartyWindow, aURI)) {
|
||||
LOG(("Our window isn't a third-party window"));
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t cookiePermission = CheckCookiePermissionForPrincipal(
|
||||
parentDocument->CookieJarSettings(), parentDocument->NodePrincipal());
|
||||
if (cookiePermission != nsICookiePermission::ACCESS_DEFAULT) {
|
||||
LOG(
|
||||
("CheckCookiePermissionForPrincipal() returned a non-default access "
|
||||
"code (%d), returning %s",
|
||||
int(cookiePermission),
|
||||
cookiePermission != nsICookiePermission::ACCESS_DENY ? "success"
|
||||
: "failure"));
|
||||
return cookiePermission != nsICookiePermission::ACCESS_DENY;
|
||||
}
|
||||
|
||||
nsAutoCString origin;
|
||||
nsresult rv = nsContentUtils::GetASCIIOrigin(aURI, origin);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
LOG_SPEC(("Failed to compute the origin from %s", _spec), aURI);
|
||||
return false;
|
||||
}
|
||||
|
||||
nsIPrincipal* parentPrincipal = parentDocument->NodePrincipal();
|
||||
|
||||
nsAutoCString type;
|
||||
AntiTrackingUtils::CreateStoragePermissionKey(origin, type);
|
||||
|
||||
return AntiTrackingUtils::CheckStoragePermission(
|
||||
parentPrincipal, type,
|
||||
nsContentUtils::IsInPrivateBrowsing(parentDocument), nullptr, 0);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -120,6 +120,42 @@ bool StoragePartitioningEnabled(StorageAccess aAccess,
|
|||
bool StoragePartitioningEnabled(uint32_t aRejectedReason,
|
||||
nsICookieJarSettings* aCookieJarSettings);
|
||||
|
||||
// This method returns true if the URI has first party storage access when
|
||||
// loaded inside the passed 3rd party context tracking resource window.
|
||||
// If the window is first party context, please use
|
||||
// ApproximateAllowAccessForWithoutChannel();
|
||||
//
|
||||
// aRejectedReason could be set to one of these values if passed and if the
|
||||
// storage permission is not granted:
|
||||
// * nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION
|
||||
// * nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER
|
||||
// * nsIWebProgressListener::STATE_COOKIES_BLOCKED_SOCIALTRACKER
|
||||
// * nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL
|
||||
// * nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN
|
||||
bool ShouldAllowAccessFor(nsPIDOMWindowInner* a3rdPartyTrackingWindow,
|
||||
nsIURI* aURI, uint32_t* aRejectedReason);
|
||||
|
||||
// Note: you should use ShouldAllowAccessFor() passing the nsIChannel! Use
|
||||
// this method _only_ if the channel is not available. For first party
|
||||
// window, it's impossible to know if the aURI is a tracking resource
|
||||
// synchronously, so here we return the best guest: if we are sure that the
|
||||
// permission is granted for the origin of aURI, this method returns true,
|
||||
// otherwise false.
|
||||
bool ApproximateAllowAccessForWithoutChannel(
|
||||
nsPIDOMWindowInner* aFirstPartyWindow, nsIURI* aURI);
|
||||
|
||||
// It returns true if the URI has access to the first party storage.
|
||||
// aChannel can be a 3rd party channel, or not.
|
||||
// See ShouldAllowAccessFor(window) to see the possible values of
|
||||
// aRejectedReason.
|
||||
bool ShouldAllowAccessFor(nsIChannel* aChannel, nsIURI* aURI,
|
||||
uint32_t* aRejectedReason);
|
||||
|
||||
// This method checks if the principal has the permission to access to the
|
||||
// first party storage.
|
||||
bool ShouldAllowAccessFor(nsIPrincipal* aPrincipal,
|
||||
nsICookieJarSettings* aCookieJarSettings);
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_StorageAccess_h
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "StoragePrincipalHelper.h"
|
||||
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
#include "mozilla/ContentBlocking.h"
|
||||
#include "mozilla/dom/WorkerPrivate.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/StaticPrefs_privacy.h"
|
||||
|
@ -31,7 +30,7 @@ bool ShouldPartitionChannel(nsIChannel* aChannel,
|
|||
}
|
||||
|
||||
uint32_t rejectedReason = 0;
|
||||
if (ContentBlocking::ShouldAllowAccessFor(aChannel, uri, &rejectedReason)) {
|
||||
if (ShouldAllowAccessFor(aChannel, uri, &rejectedReason)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче