1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "StorageAccess.h"
9 #include "mozilla/BasePrincipal.h"
10 #include "mozilla/Components.h"
11 #include "mozilla/dom/Document.h"
12 #include "mozilla/net/CookieJarSettings.h"
13 #include "mozilla/PermissionManager.h"
14 #include "mozilla/StaticPrefs_browser.h"
15 #include "mozilla/StaticPrefs_network.h"
16 #include "mozilla/StaticPrefs_privacy.h"
17 #include "mozilla/StorageAccess.h"
18 #include "nsAboutProtocolUtils.h"
19 #include "nsContentUtils.h"
20 #include "nsGlobalWindowInner.h"
21 #include "nsICookiePermission.h"
22 #include "nsICookieService.h"
23 #include "nsICookieJarSettings.h"
24 #include "nsIHttpChannel.h"
25 #include "nsIPermission.h"
26 #include "nsIWebProgressListener.h"
27 #include "nsIClassifiedChannel.h"
28 #include "nsNetUtil.h"
29 #include "nsScriptSecurityManager.h"
30 #include "nsSandboxFlags.h"
31 #include "AntiTrackingUtils.h"
32 #include "AntiTrackingLog.h"
33 #include "ContentBlockingAllowList.h"
34 #include "mozIThirdPartyUtil.h"
35 #include "RejectForeignAllowList.h"
37 using namespace mozilla
;
38 using namespace mozilla::dom
;
39 using mozilla::net::CookieJarSettings
;
41 // This internal method returns ACCESS_DENY if the access is denied,
42 // ACCESS_DEFAULT if unknown, some other access code if granted.
43 uint32_t mozilla::detail::CheckCookiePermissionForPrincipal(
44 nsICookieJarSettings
* aCookieJarSettings
, nsIPrincipal
* aPrincipal
) {
45 MOZ_ASSERT(aCookieJarSettings
);
46 MOZ_ASSERT(aPrincipal
);
48 uint32_t cookiePermission
= nsICookiePermission::ACCESS_DEFAULT
;
49 if (!aPrincipal
->GetIsContentPrincipal()) {
50 return cookiePermission
;
54 aCookieJarSettings
->CookiePermission(aPrincipal
, &cookiePermission
);
55 if (NS_WARN_IF(NS_FAILED(rv
))) {
56 return nsICookiePermission::ACCESS_DEFAULT
;
59 // If we have a custom cookie permission, let's use it.
60 return cookiePermission
;
64 * Checks if storage for a given principal is permitted by the user's
65 * preferences. If aWindow is non-null, its principal must be passed as
66 * aPrincipal, and the third-party iframe and sandboxing status of the window
67 * are also checked. If aURI is non-null, then it is used as the comparison
68 * against aWindow to determine if this is a third-party load. We also
69 * allow a channel instead of the window reference when determining 3rd party
72 * Used in the implementation of StorageAllowedForWindow,
73 * StorageAllowedForDocument, StorageAllowedForChannel and
74 * StorageAllowedForServiceWorker.
76 static StorageAccess
InternalStorageAllowedCheck(
77 nsIPrincipal
* aPrincipal
, nsPIDOMWindowInner
* aWindow
, nsIURI
* aURI
,
78 nsIChannel
* aChannel
, nsICookieJarSettings
* aCookieJarSettings
,
79 uint32_t& aRejectedReason
) {
80 MOZ_ASSERT(aPrincipal
);
84 StorageAccess access
= StorageAccess::eAllow
;
86 // We don't allow storage on the null principal, in general. Even if the
87 // calling context is chrome.
88 if (aPrincipal
->GetIsNullPrincipal()) {
89 return StorageAccess::eDeny
;
92 nsCOMPtr
<nsIURI
> documentURI
;
94 // If the document is sandboxed, then it is not permitted to use storage
95 Document
* document
= aWindow
->GetExtantDoc();
96 if (document
&& document
->GetSandboxFlags() & SANDBOXED_ORIGIN
) {
97 return StorageAccess::eDeny
;
100 // Check if we are in private browsing, and record that fact
101 if (nsContentUtils::IsInPrivateBrowsing(document
)) {
102 access
= StorageAccess::ePrivateBrowsing
;
105 // Get the document URI for the below about: URI check.
106 documentURI
= document
? document
->GetDocumentURI() : nullptr;
109 // About URIs are allowed to access storage, even if they don't have chrome
110 // privileges. If this is not desired, than the consumer will have to
111 // implement their own restriction functionality.
113 // This is due to backwards-compatibility and the state of storage access
114 // before the introducton of InternalStorageAllowedCheck:
117 // localStorage, caches: allowed in 3rd-party iframes always
118 // IndexedDB: allowed in 3rd-party iframes only if 3rd party URI is an about:
119 // URI within a specific allowlist
122 // localStorage, caches: allowed in 3rd-party iframes by default. Preference
123 // can be set to disable in 3rd-party, which will not disallow in about:
125 // IndexedDB: allowed in 3rd-party iframes by default. Preference can be set
126 // to disable in 3rd-party, which will disallow in about: URIs, unless they
127 // are within a specific allowlist.
129 // This means that behavior for storage with internal about: URIs should not
130 // be affected, which is desireable due to the lack of automated testing for
131 // about: URIs with these preferences set, and the importance of the correct
132 // functioning of these URIs even with custom preferences.
134 // We need to check the aURI or the document URI here instead of only checking
135 // the URI from the principal. Because the principal might not have a URI if
136 // it is a system principal.
137 if ((aURI
&& aURI
->SchemeIs("about") &&
138 !NS_IsContentAccessibleAboutURI(aURI
)) ||
139 (documentURI
&& documentURI
->SchemeIs("about") &&
140 !NS_IsContentAccessibleAboutURI(documentURI
)) ||
141 aPrincipal
->SchemeIs("about")) {
145 if (!StorageDisabledByAntiTracking(aWindow
, aChannel
, aPrincipal
, aURI
,
150 // We want to have a partitioned storage only for trackers.
151 if (aRejectedReason
==
152 static_cast<uint32_t>(
153 nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER
) ||
155 static_cast<uint32_t>(
156 nsIWebProgressListener::STATE_COOKIES_BLOCKED_SOCIALTRACKER
)) {
157 return StorageAccess::ePartitionTrackersOrDeny
;
160 // We want to have a partitioned storage for all third parties.
161 if (aRejectedReason
==
162 static_cast<uint32_t>(
163 nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN
)) {
164 return StorageAccess::ePartitionForeignOrDeny
;
167 return StorageAccess::eDeny
;
171 * Wrapper around InternalStorageAllowedCheck which caches the check result on
172 * the inner window to improve performance. nsGlobalWindowInner is responsible
173 * for invalidating the cache state if storage access changes during window
176 static StorageAccess
InternalStorageAllowedCheckCached(
177 nsIPrincipal
* aPrincipal
, nsPIDOMWindowInner
* aWindow
, nsIURI
* aURI
,
178 nsIChannel
* aChannel
, nsICookieJarSettings
* aCookieJarSettings
,
179 uint32_t& aRejectedReason
) {
180 // If enabled, check if we have already computed the storage access field
181 // for this window. This avoids repeated calls to
182 // InternalStorageAllowedCheck.
183 nsGlobalWindowInner
* win
= nullptr;
185 win
= nsGlobalWindowInner::Cast(aWindow
);
187 Maybe
<StorageAccess
> storageAccess
=
188 win
->GetStorageAllowedCache(aRejectedReason
);
189 if (storageAccess
.isSome()) {
190 return storageAccess
.value();
194 StorageAccess result
= InternalStorageAllowedCheck(
195 aPrincipal
, aWindow
, aURI
, aChannel
, aCookieJarSettings
, aRejectedReason
);
197 // Remember check result for the lifetime of the window. It's the windows
198 // responsibility to invalidate this field if storage access changes
199 // because a storage access permission is granted.
200 win
->SetStorageAllowedCache(result
, aRejectedReason
);
206 static bool StorageDisabledByAntiTrackingInternal(
207 nsPIDOMWindowInner
* aWindow
, nsIChannel
* aChannel
, nsIPrincipal
* aPrincipal
,
208 nsIURI
* aURI
, nsICookieJarSettings
* aCookieJarSettings
,
209 uint32_t& aRejectedReason
) {
210 MOZ_ASSERT(aWindow
|| aChannel
|| aPrincipal
);
213 nsIURI
* documentURI
= aURI
? aURI
: aWindow
->GetDocumentURI();
214 return !documentURI
||
215 !ShouldAllowAccessFor(aWindow
, documentURI
, &aRejectedReason
);
219 nsCOMPtr
<nsIURI
> uri
;
220 nsresult rv
= aChannel
->GetURI(getter_AddRefs(uri
));
221 if (NS_WARN_IF(NS_FAILED(rv
))) {
225 return !ShouldAllowAccessFor(aChannel
, uri
, &aRejectedReason
);
228 MOZ_ASSERT(aPrincipal
);
229 return !ShouldAllowAccessFor(aPrincipal
, aCookieJarSettings
);
234 StorageAccess
StorageAllowedForWindow(nsPIDOMWindowInner
* aWindow
,
235 uint32_t* aRejectedReason
) {
236 uint32_t rejectedReason
;
237 if (!aRejectedReason
) {
238 aRejectedReason
= &rejectedReason
;
241 *aRejectedReason
= 0;
243 if (Document
* document
= aWindow
->GetExtantDoc()) {
244 nsCOMPtr
<nsIPrincipal
> principal
= document
->NodePrincipal();
245 // Note that GetChannel() below may return null, but that's OK, since the
246 // callee is able to deal with a null channel argument, and if passed null,
247 // will only fail to notify the UI in case storage gets blocked.
248 nsIChannel
* channel
= document
->GetChannel();
249 return InternalStorageAllowedCheckCached(
250 principal
, aWindow
, nullptr, channel
, document
->CookieJarSettings(),
254 // No document? Try checking Private Browsing Mode without document
255 if (const nsCOMPtr
<nsIGlobalObject
> global
= aWindow
->AsGlobal()) {
256 if (const nsCOMPtr
<nsIPrincipal
> principal
= global
->PrincipalOrNull()) {
257 if (principal
->GetPrivateBrowsingId() > 0) {
258 return StorageAccess::ePrivateBrowsing
;
263 // Everything failed? Let's return a generic rejected reason.
264 return StorageAccess::eDeny
;
267 StorageAccess
StorageAllowedForDocument(const Document
* aDoc
) {
268 StorageAccess cookieAllowed
= CookieAllowedForDocument(aDoc
);
270 privacy_partition_always_partition_third_party_non_cookie_storage() &&
271 cookieAllowed
> StorageAccess::eDeny
) {
272 return StorageAccess::ePartitionForeignOrDeny
;
274 return cookieAllowed
;
277 StorageAccess
CookieAllowedForDocument(const Document
* aDoc
) {
280 if (nsPIDOMWindowInner
* inner
= aDoc
->GetInnerWindow()) {
281 nsCOMPtr
<nsIPrincipal
> principal
= aDoc
->NodePrincipal();
282 // Note that GetChannel() below may return null, but that's OK, since the
283 // callee is able to deal with a null channel argument, and if passed null,
284 // will only fail to notify the UI in case storage gets blocked.
285 nsIChannel
* channel
= aDoc
->GetChannel();
287 uint32_t rejectedReason
= 0;
288 return InternalStorageAllowedCheckCached(
289 principal
, inner
, nullptr, channel
,
290 const_cast<Document
*>(aDoc
)->CookieJarSettings(), rejectedReason
);
293 return StorageAccess::eDeny
;
296 StorageAccess
StorageAllowedForNewWindow(nsIPrincipal
* aPrincipal
, nsIURI
* aURI
,
297 nsPIDOMWindowInner
* aParent
) {
298 MOZ_ASSERT(aPrincipal
);
300 // parent may be nullptr
302 uint32_t rejectedReason
= 0;
303 nsCOMPtr
<nsICookieJarSettings
> cjs
;
304 if (aParent
&& aParent
->GetExtantDoc()) {
305 cjs
= aParent
->GetExtantDoc()->CookieJarSettings();
307 cjs
= net::CookieJarSettings::Create(aPrincipal
);
309 return InternalStorageAllowedCheck(aPrincipal
, aParent
, aURI
, nullptr, cjs
,
313 StorageAccess
StorageAllowedForChannel(nsIChannel
* aChannel
) {
314 MOZ_DIAGNOSTIC_ASSERT(nsContentUtils::GetSecurityManager());
315 MOZ_DIAGNOSTIC_ASSERT(aChannel
);
317 nsCOMPtr
<nsIPrincipal
> principal
;
318 Unused
<< nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(
319 aChannel
, getter_AddRefs(principal
));
320 NS_ENSURE_TRUE(principal
, StorageAccess::eDeny
);
322 nsCOMPtr
<nsILoadInfo
> loadInfo
= aChannel
->LoadInfo();
323 nsCOMPtr
<nsICookieJarSettings
> cookieJarSettings
;
325 loadInfo
->GetCookieJarSettings(getter_AddRefs(cookieJarSettings
));
326 NS_ENSURE_SUCCESS(rv
, StorageAccess::eDeny
);
328 uint32_t rejectedReason
= 0;
329 StorageAccess result
= InternalStorageAllowedCheck(
330 principal
, nullptr, nullptr, aChannel
, cookieJarSettings
, rejectedReason
);
335 StorageAccess
StorageAllowedForServiceWorker(
336 nsIPrincipal
* aPrincipal
, nsICookieJarSettings
* aCookieJarSettings
) {
337 uint32_t rejectedReason
= 0;
338 return InternalStorageAllowedCheck(aPrincipal
, nullptr, nullptr, nullptr,
339 aCookieJarSettings
, rejectedReason
);
342 bool StorageDisabledByAntiTracking(nsPIDOMWindowInner
* aWindow
,
343 nsIChannel
* aChannel
,
344 nsIPrincipal
* aPrincipal
, nsIURI
* aURI
,
345 uint32_t& aRejectedReason
) {
346 MOZ_ASSERT(aWindow
|| aChannel
|| aPrincipal
);
347 nsCOMPtr
<nsICookieJarSettings
> cookieJarSettings
;
349 if (aWindow
->GetExtantDoc()) {
350 cookieJarSettings
= aWindow
->GetExtantDoc()->CookieJarSettings();
352 } else if (aChannel
) {
353 nsCOMPtr
<nsILoadInfo
> loadInfo
= aChannel
->LoadInfo();
354 Unused
<< loadInfo
->GetCookieJarSettings(getter_AddRefs(cookieJarSettings
));
356 if (!cookieJarSettings
) {
357 cookieJarSettings
= net::CookieJarSettings::Create(aPrincipal
);
359 bool disabled
= StorageDisabledByAntiTrackingInternal(
360 aWindow
, aChannel
, aPrincipal
, aURI
, cookieJarSettings
, aRejectedReason
);
363 ContentBlockingNotifier::OnDecision(
365 disabled
? ContentBlockingNotifier::BlockingDecision::eBlock
366 : ContentBlockingNotifier::BlockingDecision::eAllow
,
368 } else if (aChannel
) {
369 ContentBlockingNotifier::OnDecision(
371 disabled
? ContentBlockingNotifier::BlockingDecision::eBlock
372 : ContentBlockingNotifier::BlockingDecision::eAllow
,
378 bool StorageDisabledByAntiTracking(dom::Document
* aDocument
, nsIURI
* aURI
,
379 uint32_t& aRejectedReason
) {
381 // Note that GetChannel() below may return null, but that's OK, since the
382 // callee is able to deal with a null channel argument, and if passed null,
383 // will only fail to notify the UI in case storage gets blocked.
384 return StorageDisabledByAntiTracking(
385 aDocument
->GetInnerWindow(), aDocument
->GetChannel(),
386 aDocument
->NodePrincipal(), aURI
, aRejectedReason
);
389 bool ShouldPartitionStorage(StorageAccess aAccess
) {
390 return aAccess
== StorageAccess::ePartitionTrackersOrDeny
||
391 aAccess
== StorageAccess::ePartitionForeignOrDeny
;
394 bool ShouldPartitionStorage(uint32_t aRejectedReason
) {
395 return aRejectedReason
==
396 static_cast<uint32_t>(
397 nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER
) ||
399 static_cast<uint32_t>(
400 nsIWebProgressListener::STATE_COOKIES_BLOCKED_SOCIALTRACKER
) ||
402 static_cast<uint32_t>(
403 nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN
);
406 bool StoragePartitioningEnabled(StorageAccess aAccess
,
407 nsICookieJarSettings
* aCookieJarSettings
) {
408 return aAccess
== StorageAccess::ePartitionForeignOrDeny
&&
409 aCookieJarSettings
->GetCookieBehavior() ==
410 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN
;
413 bool StoragePartitioningEnabled(uint32_t aRejectedReason
,
414 nsICookieJarSettings
* aCookieJarSettings
) {
415 return aRejectedReason
==
416 static_cast<uint32_t>(
417 nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN
) &&
418 aCookieJarSettings
->GetCookieBehavior() ==
419 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN
;
422 int32_t CookiesBehavior(Document
* a3rdPartyDocument
) {
423 MOZ_ASSERT(a3rdPartyDocument
);
425 // WebExtensions principals always get BEHAVIOR_ACCEPT as cookieBehavior
426 // (See Bug 1406675 and Bug 1525917 for rationale).
427 if (BasePrincipal::Cast(a3rdPartyDocument
->NodePrincipal())->AddonPolicy()) {
428 return nsICookieService::BEHAVIOR_ACCEPT
;
431 return a3rdPartyDocument
->CookieJarSettings()->GetCookieBehavior();
434 int32_t CookiesBehavior(nsILoadInfo
* aLoadInfo
, nsIURI
* a3rdPartyURI
) {
435 MOZ_ASSERT(aLoadInfo
);
436 MOZ_ASSERT(a3rdPartyURI
);
438 // WebExtensions 3rd party URI always get BEHAVIOR_ACCEPT as cookieBehavior,
439 // this is semantically equivalent to the principal having a AddonPolicy().
440 if (a3rdPartyURI
->SchemeIs("moz-extension")) {
441 return nsICookieService::BEHAVIOR_ACCEPT
;
444 nsCOMPtr
<nsICookieJarSettings
> cookieJarSettings
;
446 aLoadInfo
->GetCookieJarSettings(getter_AddRefs(cookieJarSettings
));
447 if (NS_WARN_IF(NS_FAILED(rv
))) {
448 return nsICookieService::BEHAVIOR_REJECT
;
451 return cookieJarSettings
->GetCookieBehavior();
454 int32_t CookiesBehavior(nsIPrincipal
* aPrincipal
,
455 nsICookieJarSettings
* aCookieJarSettings
) {
456 MOZ_ASSERT(aPrincipal
);
457 MOZ_ASSERT(aCookieJarSettings
);
459 // WebExtensions principals always get BEHAVIOR_ACCEPT as cookieBehavior
460 // (See Bug 1406675 for rationale).
461 if (BasePrincipal::Cast(aPrincipal
)->AddonPolicy()) {
462 return nsICookieService::BEHAVIOR_ACCEPT
;
465 return aCookieJarSettings
->GetCookieBehavior();
468 bool ShouldAllowAccessFor(nsPIDOMWindowInner
* aWindow
, nsIURI
* aURI
,
469 uint32_t* aRejectedReason
) {
473 // Let's avoid a null check on aRejectedReason everywhere else.
474 uint32_t rejectedReason
= 0;
475 if (!aRejectedReason
) {
476 aRejectedReason
= &rejectedReason
;
479 LOG_SPEC(("Computing whether window %p has access to URI %s", aWindow
, _spec
),
482 nsGlobalWindowInner
* innerWindow
= nsGlobalWindowInner::Cast(aWindow
);
483 Document
* document
= innerWindow
->GetExtantDoc();
485 LOG(("Our window has no document"));
489 uint32_t cookiePermission
= detail::CheckCookiePermissionForPrincipal(
490 document
->CookieJarSettings(), document
->NodePrincipal());
491 if (cookiePermission
!= nsICookiePermission::ACCESS_DEFAULT
) {
493 ("CheckCookiePermissionForPrincipal() returned a non-default access "
494 "code (%d) for window's principal, returning %s",
495 int(cookiePermission
),
496 cookiePermission
!= nsICookiePermission::ACCESS_DENY
? "success"
498 if (cookiePermission
!= nsICookiePermission::ACCESS_DENY
) {
503 nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION
;
507 int32_t behavior
= CookiesBehavior(document
);
508 if (behavior
== nsICookieService::BEHAVIOR_ACCEPT
) {
509 LOG(("The cookie behavior pref mandates accepting all cookies!"));
513 if (ContentBlockingAllowList::Check(aWindow
)) {
517 if (behavior
== nsICookieService::BEHAVIOR_REJECT
) {
518 LOG(("The cookie behavior pref mandates rejecting all cookies!"));
519 *aRejectedReason
= nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL
;
523 // As a performance optimization, we only perform this check for
524 // BEHAVIOR_REJECT_FOREIGN and BEHAVIOR_LIMIT_FOREIGN. For
525 // BEHAVIOR_REJECT_TRACKER and BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN,
526 // third-partiness is implicily checked later below.
527 if (behavior
!= nsICookieService::BEHAVIOR_REJECT_TRACKER
&&
529 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN
) {
530 // Let's check if this is a 3rd party context.
531 if (!AntiTrackingUtils::IsThirdPartyWindow(aWindow
, aURI
)) {
532 LOG(("Our window isn't a third-party window"));
537 if ((behavior
== nsICookieService::BEHAVIOR_REJECT_FOREIGN
&&
538 !CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior
)) ||
539 behavior
== nsICookieService::BEHAVIOR_LIMIT_FOREIGN
) {
540 // XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by
541 // simply rejecting the request to use the storage. In the future, if we
542 // change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense
543 // for non-cookie storage types, this may change.
544 LOG(("Nothing more to do due to the behavior code %d", int(behavior
)));
545 *aRejectedReason
= nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN
;
549 // The document has been allowlisted. We can return from here directly.
550 if (document
->HasStorageAccessPermissionGrantedByAllowList()) {
555 CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior
) ||
556 behavior
== nsICookieService::BEHAVIOR_REJECT_TRACKER
||
558 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN
);
560 uint32_t blockedReason
=
561 nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER
;
563 if (behavior
== nsICookieService::BEHAVIOR_REJECT_TRACKER
) {
564 if (!nsContentUtils::IsThirdPartyTrackingResourceWindow(aWindow
)) {
565 LOG(("Our window isn't a third-party tracking window"));
569 nsCOMPtr
<nsIClassifiedChannel
> classifiedChannel
=
570 do_QueryInterface(document
->GetChannel());
571 if (classifiedChannel
) {
572 uint32_t classificationFlags
=
573 classifiedChannel
->GetThirdPartyClassificationFlags();
574 if (classificationFlags
& nsIClassifiedChannel::ClassificationFlags::
575 CLASSIFIED_SOCIALTRACKING
) {
577 nsIWebProgressListener::STATE_COOKIES_BLOCKED_SOCIALTRACKER
;
580 } else if (behavior
==
581 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN
) {
582 if (nsContentUtils::IsThirdPartyTrackingResourceWindow(aWindow
)) {
584 } else if (AntiTrackingUtils::IsThirdPartyWindow(aWindow
, aURI
)) {
585 LOG(("We're in the third-party context, storage should be partitioned"));
586 // fall through, but remember that we're partitioning.
587 blockedReason
= nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN
;
589 LOG(("Our window isn't a third-party window, storage is allowed"));
593 MOZ_ASSERT(CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior
));
594 if (RejectForeignAllowList::Check(document
)) {
595 LOG(("This window is exceptionlisted for reject foreign"));
599 blockedReason
= nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN
;
602 Document
* doc
= aWindow
->GetExtantDoc();
603 // Make sure storage access isn't disabled
604 if (doc
&& (doc
->StorageAccessSandboxed())) {
605 LOG(("Our document is sandboxed"));
606 *aRejectedReason
= blockedReason
;
610 // Document::HasStoragePermission first checks if storage access granted is
611 // cached in the inner window, if no, it then checks the storage permission
612 // flag in the channel's loadinfo
613 bool allowed
= document
->HasStorageAccessPermissionGranted();
616 *aRejectedReason
= blockedReason
;
618 if (MOZ_LOG_TEST(gAntiTrackingLog
, mozilla::LogLevel::Debug
) &&
619 aWindow
->HasStorageAccessPermissionGranted()) {
620 LOG(("Permission stored in the window. All good."));
627 bool ShouldAllowAccessFor(nsIChannel
* aChannel
, nsIURI
* aURI
,
628 uint32_t* aRejectedReason
) {
630 MOZ_ASSERT(aChannel
);
632 // Let's avoid a null check on aRejectedReason everywhere else.
633 uint32_t rejectedReason
= 0;
634 if (!aRejectedReason
) {
635 aRejectedReason
= &rejectedReason
;
638 nsIScriptSecurityManager
* ssm
=
639 nsScriptSecurityManager::GetScriptSecurityManager();
642 nsCOMPtr
<nsIURI
> channelURI
;
643 nsresult rv
= NS_GetFinalChannelURI(aChannel
, getter_AddRefs(channelURI
));
645 LOG(("Failed to get the channel final URI, bail out early"));
649 ("Computing whether channel %p has access to URI %s", aChannel
, _spec
),
652 nsCOMPtr
<nsILoadInfo
> loadInfo
= aChannel
->LoadInfo();
653 nsCOMPtr
<nsICookieJarSettings
> cookieJarSettings
;
654 rv
= loadInfo
->GetCookieJarSettings(getter_AddRefs(cookieJarSettings
));
655 if (NS_WARN_IF(NS_FAILED(rv
))) {
657 ("Failed to get the cookie jar settings from the loadinfo, bail out "
662 nsCOMPtr
<nsIPrincipal
> channelPrincipal
;
663 rv
= ssm
->GetChannelURIPrincipal(aChannel
, getter_AddRefs(channelPrincipal
));
664 if (NS_WARN_IF(NS_FAILED(rv
))) {
665 LOG(("No channel principal, bail out early"));
669 uint32_t cookiePermission
= detail::CheckCookiePermissionForPrincipal(
670 cookieJarSettings
, channelPrincipal
);
671 if (cookiePermission
!= nsICookiePermission::ACCESS_DEFAULT
) {
673 ("CheckCookiePermissionForPrincipal() returned a non-default access "
674 "code (%d) for channel's principal, returning %s",
675 int(cookiePermission
),
676 cookiePermission
!= nsICookiePermission::ACCESS_DENY
? "success"
678 if (cookiePermission
!= nsICookiePermission::ACCESS_DENY
) {
683 nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION
;
688 LOG(("No channel uri, bail out early"));
692 int32_t behavior
= CookiesBehavior(loadInfo
, channelURI
);
693 if (behavior
== nsICookieService::BEHAVIOR_ACCEPT
) {
694 LOG(("The cookie behavior pref mandates accepting all cookies!"));
698 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(aChannel
);
700 if (httpChannel
&& ContentBlockingAllowList::Check(httpChannel
)) {
704 if (behavior
== nsICookieService::BEHAVIOR_REJECT
) {
705 LOG(("The cookie behavior pref mandates rejecting all cookies!"));
706 *aRejectedReason
= nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL
;
710 nsCOMPtr
<mozIThirdPartyUtil
> thirdPartyUtil
=
711 components::ThirdPartyUtil::Service();
712 if (!thirdPartyUtil
) {
713 LOG(("No thirdPartyUtil, bail out early"));
717 bool thirdParty
= false;
718 rv
= thirdPartyUtil
->IsThirdPartyChannel(aChannel
, aURI
, &thirdParty
);
719 // Grant if it's not a 3rd party.
720 // Be careful to check the return value of IsThirdPartyChannel, since
721 // IsThirdPartyChannel() will fail if the channel's loading principal is the
722 // system principal...
723 if (NS_SUCCEEDED(rv
) && !thirdParty
) {
724 LOG(("Our channel isn't a third-party channel"));
728 if ((behavior
== nsICookieService::BEHAVIOR_REJECT_FOREIGN
&&
729 !CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior
)) ||
730 behavior
== nsICookieService::BEHAVIOR_LIMIT_FOREIGN
) {
731 // XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by
732 // simply rejecting the request to use the storage. In the future, if we
733 // change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense
734 // for non-cookie storage types, this may change.
735 LOG(("Nothing more to do due to the behavior code %d", int(behavior
)));
736 *aRejectedReason
= nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN
;
740 // The channel has been allowlisted. We can return from here.
741 if (loadInfo
->GetStoragePermission() ==
742 nsILoadInfo::StoragePermissionAllowListed
) {
747 CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior
) ||
748 behavior
== nsICookieService::BEHAVIOR_REJECT_TRACKER
||
750 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN
);
752 uint32_t blockedReason
=
753 nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER
;
756 nsCOMPtr
<nsIClassifiedChannel
> classifiedChannel
=
757 do_QueryInterface(aChannel
);
758 if (behavior
== nsICookieService::BEHAVIOR_REJECT_TRACKER
) {
759 if (classifiedChannel
) {
760 if (!classifiedChannel
->IsThirdPartyTrackingResource()) {
761 LOG(("Our channel isn't a third-party tracking channel"));
765 uint32_t classificationFlags
=
766 classifiedChannel
->GetThirdPartyClassificationFlags();
767 if (classificationFlags
& nsIClassifiedChannel::ClassificationFlags::
768 CLASSIFIED_SOCIALTRACKING
) {
770 nsIWebProgressListener::STATE_COOKIES_BLOCKED_SOCIALTRACKER
;
773 } else if (behavior
==
774 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN
) {
775 if (classifiedChannel
&&
776 classifiedChannel
->IsThirdPartyTrackingResource()) {
778 } else if (AntiTrackingUtils::IsThirdPartyChannel(aChannel
)) {
779 LOG(("We're in the third-party context, storage should be partitioned"));
780 // fall through but remember that we're partitioning.
781 blockedReason
= nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN
;
783 LOG(("Our channel isn't a third-party channel, storage is allowed"));
787 MOZ_ASSERT(CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior
));
788 if (httpChannel
&& RejectForeignAllowList::Check(httpChannel
)) {
789 LOG(("This channel is exceptionlisted"));
792 blockedReason
= nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN
;
795 RefPtr
<BrowsingContext
> targetBC
;
796 rv
= loadInfo
->GetTargetBrowsingContext(getter_AddRefs(targetBC
));
797 if (!targetBC
|| NS_WARN_IF(NS_FAILED(rv
))) {
798 LOG(("Failed to get the channel's target browsing context"));
802 if (Document::StorageAccessSandboxed(targetBC
->GetSandboxFlags())) {
803 LOG(("Our document is sandboxed"));
804 *aRejectedReason
= blockedReason
;
808 // Let's see if we have to grant the access for this particular channel.
810 // HasStorageAccessPermissionGranted only applies to channels that load
811 // documents, for sub-resources loads, just returns the result from loadInfo.
812 bool isDocument
= false;
813 aChannel
->GetIsDocument(&isDocument
);
816 nsCOMPtr
<nsPIDOMWindowInner
> inner
=
817 AntiTrackingUtils::GetInnerWindow(targetBC
);
818 if (inner
&& inner
->HasStorageAccessPermissionGranted()) {
819 LOG(("Permission stored in the window. All good."));
825 loadInfo
->GetStoragePermission() != nsILoadInfo::NoStoragePermission
;
827 *aRejectedReason
= blockedReason
;
833 bool ShouldAllowAccessFor(nsIPrincipal
* aPrincipal
,
834 nsICookieJarSettings
* aCookieJarSettings
) {
835 MOZ_ASSERT(aPrincipal
);
836 MOZ_ASSERT(aCookieJarSettings
);
838 uint32_t access
= nsICookiePermission::ACCESS_DEFAULT
;
839 if (aPrincipal
->GetIsContentPrincipal()) {
840 PermissionManager
* permManager
= PermissionManager::GetInstance();
842 Unused
<< NS_WARN_IF(NS_FAILED(permManager
->TestPermissionFromPrincipal(
843 aPrincipal
, "cookie"_ns
, &access
)));
847 if (access
!= nsICookiePermission::ACCESS_DEFAULT
) {
848 return access
!= nsICookiePermission::ACCESS_DENY
;
851 int32_t behavior
= CookiesBehavior(aPrincipal
, aCookieJarSettings
);
852 return behavior
!= nsICookieService::BEHAVIOR_REJECT
;
856 bool ApproximateAllowAccessForWithoutChannel(
857 nsPIDOMWindowInner
* aFirstPartyWindow
, nsIURI
* aURI
) {
858 MOZ_ASSERT(aFirstPartyWindow
);
862 ("Computing a best guess as to whether window %p has access to URI %s",
863 aFirstPartyWindow
, _spec
),
866 Document
* parentDocument
=
867 nsGlobalWindowInner::Cast(aFirstPartyWindow
)->GetExtantDoc();
868 if (NS_WARN_IF(!parentDocument
)) {
869 LOG(("Failed to get the first party window's document"));
873 if (!parentDocument
->CookieJarSettings()->GetRejectThirdPartyContexts()) {
874 LOG(("Disabled by the pref (%d), bail out early",
875 parentDocument
->CookieJarSettings()->GetCookieBehavior()));
879 if (ContentBlockingAllowList::Check(aFirstPartyWindow
)) {
883 if (!AntiTrackingUtils::IsThirdPartyWindow(aFirstPartyWindow
, aURI
)) {
884 LOG(("Our window isn't a third-party window"));
888 uint32_t cookiePermission
= detail::CheckCookiePermissionForPrincipal(
889 parentDocument
->CookieJarSettings(), parentDocument
->NodePrincipal());
890 if (cookiePermission
!= nsICookiePermission::ACCESS_DEFAULT
) {
892 ("CheckCookiePermissionForPrincipal() returned a non-default access "
893 "code (%d), returning %s",
894 int(cookiePermission
),
895 cookiePermission
!= nsICookiePermission::ACCESS_DENY
? "success"
897 return cookiePermission
!= nsICookiePermission::ACCESS_DENY
;
900 nsIPrincipal
* parentPrincipal
= parentDocument
->NodePrincipal();
902 nsCOMPtr
<nsIPrincipal
> principal
= BasePrincipal::CreateContentPrincipal(
903 aURI
, parentPrincipal
->OriginAttributesRef());
906 AntiTrackingUtils::CreateStoragePermissionKey(principal
, type
);
908 return AntiTrackingUtils::CheckStoragePermission(
909 parentPrincipal
, type
,
910 nsContentUtils::IsInPrivateBrowsing(parentDocument
), nullptr, 0);
912 } // namespace mozilla