Bug 1480780 - Merge the privacy.3rdpartystorage.enabled pref with the network.cookie.cookieBehavior pref; r=ehsan

This patch introduces a new cookie behavior policy called
BEHAVIOR_REJECT_TRACKER.  It also makes it possible to override that
behavior with cookie permissions similar to other cookie behaviors.
This commit is contained in:
Andrea Marchesini 2018-08-10 15:55:22 -04:00 коммит произвёл Ehsan Akhgari
Родитель d65b9942a2
Коммит d1e5833a37
20 изменённых файлов: 320 добавлений и 195 удалений

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

@ -11,6 +11,7 @@
#include "nsIXULAppInfo.h"
#include "nsPluginArray.h"
#include "nsMimeTypeArray.h"
#include "mozilla/AntiTrackingCommon.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/dom/BodyExtractor.h"
#include "mozilla/dom/FetchBinding.h"
@ -63,6 +64,7 @@
#include "nsRFPService.h"
#include "nsStringStream.h"
#include "nsComponentManagerUtils.h"
#include "nsICookieService.h"
#include "nsIStringStream.h"
#include "nsIHttpChannel.h"
#include "nsIHttpChannelInternal.h"
@ -513,15 +515,11 @@ Navigator::Storage()
return mStorageManager;
}
// Values for the network.cookie.cookieBehavior pref are documented in
// nsCookieService.cpp.
#define COOKIE_BEHAVIOR_REJECT 2
bool
Navigator::CookieEnabled()
{
bool cookieEnabled = (StaticPrefs::network_cookie_cookieBehavior() !=
COOKIE_BEHAVIOR_REJECT);
nsICookieService::BEHAVIOR_REJECT);
// Check whether an exception overrides the global cookie behavior
// Note that the code for getting the URI here matches that in
@ -544,20 +542,8 @@ Navigator::CookieEnabled()
return cookieEnabled;
}
nsCOMPtr<nsICookiePermission> permMgr =
do_GetService(NS_COOKIEPERMISSION_CONTRACTID);
NS_ENSURE_TRUE(permMgr, cookieEnabled);
// Pass null for the channel, just like the cookie service does.
nsCookieAccess access;
nsresult rv = permMgr->CanAccess(doc->NodePrincipal(), &access);
NS_ENSURE_SUCCESS(rv, cookieEnabled);
if (access != nsICookiePermission::ACCESS_DEFAULT) {
cookieEnabled = access != nsICookiePermission::ACCESS_DENY;
}
return cookieEnabled;
return AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(mWindow,
codebaseURI);
}
bool

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

@ -217,8 +217,8 @@
#include "HTMLSplitOnSpacesTokenizer.h"
#include "nsContentTypeParser.h"
#include "nsICookiePermission.h"
#include "mozIThirdPartyUtil.h"
#include "nsICookieService.h"
#include "mozIThirdPartyUtil.h"
#include "mozilla/EnumSet.h"
#include "mozilla/BloomFilter.h"
#include "TabChild.h"
@ -8751,12 +8751,10 @@ nsContentUtils::StorageAllowedForPrincipal(nsIPrincipal* aPrincipal)
// static, private
void
nsContentUtils::GetCookieBehaviorForPrincipal(nsIPrincipal* aPrincipal,
uint32_t* aLifetimePolicy,
uint32_t* aBehavior)
nsContentUtils::GetCookieLifetimePolicyForPrincipal(nsIPrincipal* aPrincipal,
uint32_t* aLifetimePolicy)
{
*aLifetimePolicy = sCookiesLifetimePolicy;
*aBehavior = StaticPrefs::network_cookie_cookieBehavior();
// Any permissions set for the given principal will override our default
// settings from preferences.
@ -8770,19 +8768,15 @@ nsContentUtils::GetCookieBehaviorForPrincipal(nsIPrincipal* aPrincipal,
permissionManager->TestPermissionFromPrincipal(aPrincipal, "cookie", &perm);
switch (perm) {
case nsICookiePermission::ACCESS_ALLOW:
*aBehavior = nsICookieService::BEHAVIOR_ACCEPT;
*aLifetimePolicy = nsICookieService::ACCEPT_NORMALLY;
break;
case nsICookiePermission::ACCESS_DENY:
*aBehavior = nsICookieService::BEHAVIOR_REJECT;
*aLifetimePolicy = nsICookieService::ACCEPT_NORMALLY;
break;
case nsICookiePermission::ACCESS_SESSION:
*aBehavior = nsICookieService::BEHAVIOR_ACCEPT;
*aLifetimePolicy = nsICookieService::ACCEPT_SESSION;
break;
case nsICookiePermission::ACCESS_ALLOW_FIRST_PARTY_ONLY:
*aBehavior = nsICookieService::BEHAVIOR_REJECT_FOREIGN;
// NOTE: The decision was made here to override the lifetime policy to be
// ACCEPT_NORMALLY for consistency with ACCESS_ALLOW, but this does
// prevent us from expressing BEHAVIOR_REJECT_FOREIGN/ACCEPT_SESSION for a
@ -8791,7 +8785,6 @@ nsContentUtils::GetCookieBehaviorForPrincipal(nsIPrincipal* aPrincipal,
*aLifetimePolicy = nsICookieService::ACCEPT_NORMALLY;
break;
case nsICookiePermission::ACCESS_LIMIT_THIRD_PARTY:
*aBehavior = nsICookieService::BEHAVIOR_LIMIT_FOREIGN;
// NOTE: The decision was made here to override the lifetime policy to be
// ACCEPT_NORMALLY for consistency with ACCESS_ALLOW, but this does
// prevent us from expressing BEHAVIOR_REJECT_FOREIGN/ACCEPT_SESSION for a
@ -8861,71 +8854,47 @@ nsContentUtils::IsTrackingResourceWindow(nsPIDOMWindowInner* aWindow)
static bool
StorageDisabledByAntiTrackingInternal(nsPIDOMWindowInner* aWindow,
nsIChannel* aChannel,
nsIPrincipal* aPrincipal,
nsIURI* aURI)
{
if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) {
return false;
}
// Let's check if this is a 3rd party context.
if (!nsContentUtils::IsThirdPartyWindowOrChannel(aWindow, aChannel, aURI)) {
return false;
}
MOZ_ASSERT(aWindow || aChannel || aPrincipal);
if (aWindow) {
nsGlobalWindowInner* innerWindow = nsGlobalWindowInner::Cast(aWindow);
nsGlobalWindowOuter* outerWindow =
nsGlobalWindowOuter::Cast(innerWindow->GetOuterWindow());
if (NS_WARN_IF(!outerWindow)) {
return false;
}
// We are a first party resource.
if (outerWindow->IsTopLevelWindow()) {
return false;
}
nsIURI* documentURI = aURI ? aURI : aWindow->GetDocumentURI();
if (documentURI &&
AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(aWindow,
documentURI)) {
return false;
return !documentURI ||
!AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(aWindow,
documentURI);
}
return true;
}
// aChannel and aWindow are mutually exclusive.
MOZ_ASSERT(aChannel);
if (aChannel) {
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
if (!httpChannel) {
return false;
}
// If this is not a tracking resource, nothing is disabled.
if (!httpChannel->GetIsTrackingResource()) {
return false;
}
nsCOMPtr<nsIURI> uri;
nsresult rv = httpChannel->GetURI(getter_AddRefs(uri));
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
return AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(httpChannel,
return !AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(httpChannel,
uri);
}
MOZ_ASSERT(aPrincipal);
return !AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(aPrincipal);
}
// static public
bool
nsContentUtils::StorageDisabledByAntiTracking(nsPIDOMWindowInner* aWindow,
nsIChannel* aChannel,
nsIPrincipal* aPrincipal,
nsIURI* aURI)
{
bool disabled =
StorageDisabledByAntiTrackingInternal(aWindow, aChannel, aURI);
StorageDisabledByAntiTrackingInternal(aWindow, aChannel, aPrincipal, aURI);
if (disabled &&
StaticPrefs::privacy_restrict3rdpartystorage_ui_enabled()) {
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = services::GetThirdPartyUtil();
@ -8933,6 +8902,8 @@ nsContentUtils::StorageDisabledByAntiTracking(nsPIDOMWindowInner* aWindow,
return false;
}
// FIXME: this is wrong. This method is called also with aWindow and a null
// aChannel.
nsCOMPtr<mozIDOMWindowProxy> win;
nsresult rv = thirdPartyUtil->GetTopWindowForChannel(aChannel,
getter_AddRefs(win));
@ -8962,10 +8933,6 @@ nsContentUtils::InternalStorageAllowedForPrincipal(nsIPrincipal* aPrincipal,
return StorageAccess::eDeny;
}
if (StorageDisabledByAntiTracking(aWindow, aChannel, aURI)) {
return StorageAccess::eDeny;
}
if (aWindow) {
// If the document is sandboxed, then it is not permitted to use storage
nsIDocument* document = aWindow->GetExtantDoc();
@ -8980,17 +8947,15 @@ nsContentUtils::InternalStorageAllowedForPrincipal(nsIPrincipal* aPrincipal,
}
uint32_t lifetimePolicy;
uint32_t behavior;
// WebExtensions principals always get BEHAVIOR_ACCEPT as cookieBehavior
// and ACCEPT_NORMALLY as lifetimePolicy (See Bug 1406675 for rationale).
auto policy = BasePrincipal::Cast(aPrincipal)->AddonPolicy();
if (policy) {
behavior = nsICookieService::BEHAVIOR_ACCEPT;
lifetimePolicy = nsICookieService::ACCEPT_NORMALLY;
} else {
GetCookieBehaviorForPrincipal(aPrincipal, &lifetimePolicy, &behavior);
GetCookieLifetimePolicyForPrincipal(aPrincipal, &lifetimePolicy);
}
// Check if we should only allow storage for the session, and record that fact
@ -9036,19 +9001,7 @@ nsContentUtils::InternalStorageAllowedForPrincipal(nsIPrincipal* aPrincipal,
}
}
// We don't want to prompt for every attempt to access permissions.
if (behavior == nsICookieService::BEHAVIOR_REJECT) {
return StorageAccess::eDeny;
}
if ((behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN ||
behavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) &&
IsThirdPartyWindowOrChannel(aWindow, aChannel, aURI)) {
// 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.
if (StorageDisabledByAntiTracking(aWindow, aChannel, aPrincipal, aURI)) {
return StorageAccess::eDeny;
}

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

@ -2951,11 +2951,12 @@ public:
static StorageAccess StorageAllowedForPrincipal(nsIPrincipal* aPrincipal);
/*
* Returns true if this window/channel should disable storages because of the
* anti-tracking feature.
* Returns true if this window/channel/aPrincipal should disable storages
* because of the anti-tracking feature.
*/
static bool StorageDisabledByAntiTracking(nsPIDOMWindowInner* aWindow,
nsIChannel* aChannel,
nsIPrincipal* aPrincipal,
nsIURI* aURI);
/*
@ -3342,14 +3343,13 @@ private:
void* aArg);
/**
* Gets the current cookie lifetime policy and cookie behavior for a given
* principal by checking with preferences and the permission manager.
* Gets the current cookie lifetime policy for a given principal by checking
* with preferences and the permission manager.
*
* Used in the implementation of InternalStorageAllowedForPrincipal.
*/
static void GetCookieBehaviorForPrincipal(nsIPrincipal* aPrincipal,
uint32_t* aLifetimePolicy,
uint32_t* aBehavior);
static void GetCookieLifetimePolicyForPrincipal(nsIPrincipal* aPrincipal,
uint32_t* aLifetimePolicy);
/*
* Checks if storage for a given principal is permitted by the user's

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

@ -12643,7 +12643,8 @@ nsIDocument::SetDocTreeHadPlayRevoked()
void
nsIDocument::MaybeAllowStorageForOpener()
{
if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) {
if (StaticPrefs::network_cookie_cookieBehavior() !=
nsICookieService::BEHAVIOR_REJECT_TRACKER) {
return;
}

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

@ -17,10 +17,10 @@
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/BackgroundUtils.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "mozilla/StaticPrefs.h"
#include "nsContentUtils.h"
#include "nsIBFCacheEntry.h"
#include "nsICookieService.h"
#include "nsIDocument.h"
#include "nsISupportsPrimitives.h"
@ -73,12 +73,14 @@ class InitializeRunnable final : public WorkerMainThreadRunnable
{
public:
InitializeRunnable(ThreadSafeWorkerRef* aWorkerRef, nsACString& aOrigin,
PrincipalInfo& aPrincipalInfo, ErrorResult& aRv)
PrincipalInfo& aPrincipalInfo, bool* aThirdPartyWindow,
ErrorResult& aRv)
: WorkerMainThreadRunnable(aWorkerRef->Private(),
NS_LITERAL_CSTRING("BroadcastChannel :: Initialize"))
, mWorkerRef(aWorkerRef)
, mOrigin(aOrigin)
, mPrincipalInfo(aPrincipalInfo)
, mThirdPartyWindow(aThirdPartyWindow)
, mRv(aRv)
{
MOZ_ASSERT(mWorkerRef);
@ -116,6 +118,9 @@ public:
return true;
}
*mThirdPartyWindow =
nsContentUtils::IsThirdPartyWindowOrChannel(window, nullptr, nullptr);
return true;
}
@ -123,6 +128,7 @@ private:
RefPtr<ThreadSafeWorkerRef> mWorkerRef;
nsACString& mOrigin;
PrincipalInfo& mPrincipalInfo;
bool* mThirdPartyWindow;
ErrorResult& mRv;
};
@ -301,7 +307,8 @@ BroadcastChannel::Constructor(const GlobalObject& aGlobal,
return nullptr;
}
if (StaticPrefs::privacy_restrict3rdpartystorage_enabled() &&
if (nsContentUtils::IsThirdPartyWindowOrChannel(window, nullptr,
nullptr) &&
nsContentUtils::StorageAllowedForWindow(window) !=
nsContentUtils::StorageAccess::eAllow) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
@ -313,12 +320,6 @@ BroadcastChannel::Constructor(const GlobalObject& aGlobal,
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
MOZ_ASSERT(workerPrivate);
if (StaticPrefs::privacy_restrict3rdpartystorage_enabled() &&
!workerPrivate->IsStorageAllowed()) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
}
RefPtr<StrongWorkerRef> workerRef =
StrongWorkerRef::Create(workerPrivate, "BroadcastChannel",
[bc] () { bc->Shutdown(); });
@ -331,13 +332,21 @@ BroadcastChannel::Constructor(const GlobalObject& aGlobal,
RefPtr<ThreadSafeWorkerRef> tsr = new ThreadSafeWorkerRef(workerRef);
bool thirdPartyWindow = false;
RefPtr<InitializeRunnable> runnable =
new InitializeRunnable(tsr, origin, principalInfo, aRv);
new InitializeRunnable(tsr, origin, principalInfo, &thirdPartyWindow,
aRv);
runnable->Dispatch(Canceling, aRv);
if (aRv.Failed()) {
return nullptr;
}
if (thirdPartyWindow && !workerPrivate->IsStorageAllowed()) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
}
bc->mWorkerRef = std::move(workerRef);
}

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

@ -1107,7 +1107,7 @@ nsHTMLDocument::GetCookie(nsAString& aCookie, ErrorResult& rv)
}
if (nsContentUtils::StorageDisabledByAntiTracking(GetInnerWindow(), nullptr,
nullptr)) {
NodePrincipal(), nullptr)) {
return;
}
@ -1162,7 +1162,7 @@ nsHTMLDocument::SetCookie(const nsAString& aCookie, ErrorResult& rv)
}
if (nsContentUtils::StorageDisabledByAntiTracking(GetInnerWindow(), nullptr,
nullptr)) {
NodePrincipal(), nullptr)) {
return;
}

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

@ -9,6 +9,7 @@
#include "nsAutoPtr.h"
#include "nsIChannel.h"
#include "nsIContentSecurityPolicy.h"
#include "nsICookieService.h"
#include "nsIDocument.h"
#include "nsIDOMChromeWindow.h"
#include "nsIEffectiveTLDService.h"
@ -2268,7 +2269,8 @@ RuntimeService::PropagateFirstPartyStorageAccessGranted(nsPIDOMWindowInner* aWin
{
AssertIsOnMainThread();
MOZ_ASSERT(aWindow);
MOZ_ASSERT(StaticPrefs::privacy_restrict3rdpartystorage_enabled());
MOZ_ASSERT(StaticPrefs::network_cookie_cookieBehavior() ==
nsICookieService::BEHAVIOR_REJECT_TRACKER);
nsTArray<WorkerPrivate*> workers;
GetWorkersForWindow(aWindow, workers);
@ -2881,7 +2883,8 @@ void
PropagateFirstPartyStorageAccessGrantedToWorkers(nsPIDOMWindowInner* aWindow)
{
AssertIsOnMainThread();
MOZ_ASSERT(StaticPrefs::privacy_restrict3rdpartystorage_enabled());
MOZ_ASSERT(StaticPrefs::network_cookie_cookieBehavior() ==
nsICookieService::BEHAVIOR_REJECT_TRACKER);
RuntimeService* runtime = RuntimeService::GetService();
if (runtime) {

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

@ -8,13 +8,13 @@
#include "mozilla/HashFunctions.h"
#include "mozilla/Move.h"
#include "nsContentUtils.h"
#include "nsICookieService.h"
#include "nsLayoutUtils.h"
#include "nsString.h"
#include "mozilla/AntiTrackingCommon.h"
#include "mozilla/dom/BlobURLProtocolHandler.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/ServiceWorkerManager.h"
#include "mozilla/StaticPrefs.h"
#include "nsIDocument.h"
#include "nsPrintfCString.h"
@ -141,20 +141,13 @@ ImageCacheKey::GetSpecialCaseDocumentToken(nsIDocument* aDocument, nsIURI* aURI)
return aDocument;
}
// We want to have a unique image cache if the anti-tracking feature is
// enabled for 3rd party resources.
if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled() ||
!nsContentUtils::IsThirdPartyWindowOrChannel(aDocument->GetInnerWindow(),
nullptr, aURI)) {
return nullptr;
}
// If the window is 3rd party resource, let's see if the first party storage
// access is granted for this image.
if (nsContentUtils::IsTrackingResourceWindow(aDocument->GetInnerWindow())) {
return nsContentUtils::StorageDisabledByAntiTracking(aDocument->GetInnerWindow(),
nullptr, aURI)
? aDocument : nullptr;
// If we must disable the storage, we want to create a unique cache key for
// this image.
if (nsContentUtils::StorageDisabledByAntiTracking(aDocument->GetInnerWindow(),
nullptr,
aDocument->NodePrincipal(),
aURI)) {
return aDocument;
}
// Another scenario is if this image is a 3rd party resource loaded by a
@ -163,7 +156,8 @@ ImageCacheKey::GetSpecialCaseDocumentToken(nsIDocument* 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 a nullptr. Otherwise, let's
// make a unique image cache.
if (!AntiTrackingCommon::MaybeIsFirstPartyStorageAccessGrantedFor(aDocument->GetInnerWindow(),
if (!aDocument->IsCookieAverse() &&
!AntiTrackingCommon::MaybeIsFirstPartyStorageAccessGrantedFor(aDocument->GetInnerWindow(),
aURI)) {
return aDocument;
}

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

@ -1091,12 +1091,13 @@ VARCACHE_PREF(
bool, false
)
// 0-Accept, 1-dontAcceptForeign, 2-dontAcceptAny, 3-limitForeign
// 0-Accept, 1-dontAcceptForeign, 2-dontAcceptAny, 3-limitForeign,
// 4-rejectTracker
// Keep the old default of accepting all cookies
VARCACHE_PREF(
"network.cookie.cookieBehavior",
network_cookie_cookieBehavior,
int32_t, 0
RelaxedAtomicInt32, 0
)
// Enables the predictive service.
@ -1231,12 +1232,6 @@ PREF("preferences.allow.omt-write", bool, true)
// Privacy prefs
//---------------------------------------------------------------------------
VARCACHE_PREF(
"privacy.restrict3rdpartystorage.enabled",
privacy_restrict3rdpartystorage_enabled,
RelaxedAtomicBool, false
)
VARCACHE_PREF(
"privacy.restrict3rdpartystorage.ui.enabled",
privacy_restrict3rdpartystorage_ui_enabled,

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

@ -12,6 +12,7 @@
#include "nsIAddonPolicyService.h"
#include "nsICacheEntry.h"
#include "nsICachingChannel.h"
#include "nsICookieService.h"
#include "nsIChannel.h"
#include "nsIClassOfService.h"
#include "nsIDocShell.h"
@ -951,7 +952,8 @@ TrackingURICallback::OnClassifyComplete(nsresult aErrorCode,
mChannelClassifier->ShouldEnableTrackingProtection();
const bool shouldEnableTrackingAnnotation =
mChannelClassifier->ShouldEnableTrackingAnnotation() ||
StaticPrefs::privacy_restrict3rdpartystorage_enabled();
StaticPrefs::network_cookie_cookieBehavior() ==
nsICookieService::BEHAVIOR_REJECT_TRACKER;
MOZ_ASSERT(shouldEnableTrackingProtection || shouldEnableTrackingAnnotation);
LOG(("TrackingURICallback[%p]:OnClassifyComplete "
@ -1199,7 +1201,8 @@ TrackingURICallback::OnTrackerFound(nsresult aErrorCode)
} else {
MOZ_ASSERT(aErrorCode == NS_ERROR_TRACKING_ANNOTATION_URI);
MOZ_ASSERT(mChannelClassifier->ShouldEnableTrackingAnnotation() ||
StaticPrefs::privacy_restrict3rdpartystorage_enabled());
StaticPrefs::network_cookie_cookieBehavior() ==
nsICookieService::BEHAVIOR_REJECT_TRACKER);
LOG(("TrackingURICallback[%p]::OnTrackerFound, annotating channel[%p]",
mChannelClassifier.get(), channel.get()));
@ -1421,7 +1424,8 @@ nsChannelClassifier::CheckIsTrackerWithLocalTable(std::function<void()>&& aCallb
}
const bool shouldEnableTrackingProtection = ShouldEnableTrackingProtection();
const bool shouldEnableTrackingAnnotation = ShouldEnableTrackingAnnotation() || StaticPrefs::privacy_restrict3rdpartystorage_enabled();
const bool shouldEnableTrackingAnnotation = ShouldEnableTrackingAnnotation() ||
StaticPrefs::network_cookie_cookieBehavior() == nsICookieService::BEHAVIOR_REJECT_TRACKER;
if (!shouldEnableTrackingProtection && !shouldEnableTrackingAnnotation) {
return NS_ERROR_FAILURE;
}

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

@ -2410,7 +2410,7 @@ nsCookieService::PrefChanged(nsIPrefBranch *aPrefBranch)
{
int32_t val;
if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefCookieBehavior, &val)))
mCookieBehavior = (uint8_t) LIMIT(val, 0, 3, 0);
mCookieBehavior = (uint8_t) LIMIT(val, 0, nsICookieService::BEHAVIOR_LAST, 0);
if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefMaxNumberOfCookies, &val)))
mMaxNumberOfCookies = (uint16_t) LIMIT(val, 1, 0xFFFF, kMaxNumberOfCookies);
@ -4199,14 +4199,6 @@ nsCookieService::CheckPrefs(nsICookiePermission *aPermissionService,
return STATUS_REJECTED_WITH_ERROR;
}
// No cookies allowed if this request comes from a tracker, in a 3rd party
// context, when anti-tracking protection is enabled and when we don't have
// access to the first-party cookie jar.
if (aIsForeign && aIsTrackingResource && !aFirstPartyStorageAccessGranted &&
StaticPrefs::privacy_restrict3rdpartystorage_enabled()) {
return STATUS_REJECTED;
}
// check the permission list first; if we find an entry, it overrides
// default prefs. see bug 184059.
if (aPermissionService) {
@ -4250,6 +4242,15 @@ nsCookieService::CheckPrefs(nsICookiePermission *aPermissionService,
}
}
// No cookies allowed if this request comes from a tracker, in a 3rd party
// context, when anti-tracking protection is enabled and when we don't have
// access to the first-party cookie jar.
if (aIsForeign && aIsTrackingResource && !aFirstPartyStorageAccessGranted &&
aCookieBehavior == nsICookieService::BEHAVIOR_REJECT_TRACKER) {
COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "cookies are disabled in trackers");
return STATUS_REJECTED;
}
// check default prefs
if (aCookieBehavior == nsICookieService::BEHAVIOR_REJECT) {
COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "cookies are disabled");
@ -4271,7 +4272,9 @@ nsCookieService::CheckPrefs(nsICookiePermission *aPermissionService,
}
MOZ_ASSERT(aCookieBehavior == nsICookieService::BEHAVIOR_ACCEPT ||
aCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN);
aCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN ||
// But with permission granted.
aCookieBehavior == nsICookieService::BEHAVIOR_REJECT_TRACKER);
if (aThirdPartySession)
return STATUS_ACCEPT_SESSION;

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

@ -52,7 +52,7 @@ interface nsICookiePermission : nsISupports
/**
* canAccess
*
* this method is called to test whether or not the given URI/channel may
* this method is called to test whether or not the given principal may
* access the cookie database, either to set or get cookies.
*
* @param aPrincipal

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

@ -89,6 +89,9 @@ interface nsICookieService : nsISupports
const uint32_t BEHAVIOR_REJECT = 2; // reject all cookies
const uint32_t BEHAVIOR_LIMIT_FOREIGN = 3; // reject third-party cookies unless the
// eTLD already has at least one cookie
const uint32_t BEHAVIOR_REJECT_TRACKER = 4; // reject trackers
// When adding a new cookie behavior, please increase this value!
const uint32_t BEHAVIOR_LAST = 4;
/*
* Possible values for the "network.cookie.lifetimePolicy" preference.

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

@ -22,6 +22,7 @@
#include "nsICacheStorage.h"
#include "nsICacheEntry.h"
#include "nsICaptivePortalService.h"
#include "nsICookieService.h"
#include "nsICryptoHash.h"
#include "nsINetworkInterceptController.h"
#include "nsINSSErrorsService.h"
@ -55,6 +56,7 @@
#include "nsThreadUtils.h"
#include "GeckoProfiler.h"
#include "nsIConsoleService.h"
#include "mozilla/AntiTrackingCommon.h"
#include "mozilla/Attributes.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/Preferences.h"
@ -103,7 +105,6 @@
#include "mozilla/net/Predictor.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/NullPrincipal.h"
#include "mozilla/StaticPrefs.h"
#include "CacheControlParser.h"
#include "nsMixedContentBlocker.h"
#include "CacheStorageService.h"
@ -3827,29 +3828,19 @@ nsHttpChannel::OpenCacheEntryInternal(bool isHttps,
extension.Append("TRR");
}
if (StaticPrefs::privacy_restrict3rdpartystorage_enabled() &&
mIsTrackingResource) {
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
services::GetThirdPartyUtil();
if (thirdPartyUtil) {
bool thirdParty = false;
Unused << thirdPartyUtil->IsThirdPartyChannel(this,
nullptr,
&thirdParty);
if (thirdParty) {
if (!AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(this, mURI)) {
nsCOMPtr<nsIURI> topWindowURI;
rv = GetTopWindowURI(getter_AddRefs(topWindowURI));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString topWindowOrigin;
rv = nsContentUtils::GetUTFOrigin(topWindowURI, topWindowOrigin);
rv = nsContentUtils::GetUTFOrigin(topWindowURI ? topWindowURI : mURI,
topWindowOrigin);
NS_ENSURE_SUCCESS(rv, rv);
extension.Append("-trackerFor:");
extension.Append("-unique:");
extension.Append(NS_ConvertUTF16toUTF8(topWindowOrigin));
}
}
}
mCacheOpenWithPriority = cacheEntryOpenFlags & nsICacheStorage::OPEN_PRIORITY;
mCacheQueueSizeWhenOpen = CacheStorageService::CacheQueueSize(mCacheOpenWithPriority);

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

@ -479,7 +479,7 @@ interface nsIHttpChannel : nsIChannel
* protection list. This is only available if the
* privacy.trackingprotection.annotate_channels pref is set and its value
* should only be relied on after the channel has established a connection.
* Note that, if privacy.restrict3rdpartystorage.enabled pref is set, also
* Note that, if the privacy.trackingprotection.annotate_channels pref is set, also
* top-level channels could be marked as tracking resource.
*/
[infallible] readonly attribute boolean isTrackingResource;

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

@ -13,10 +13,13 @@
#include "mozIThirdPartyUtil.h"
#include "nsContentUtils.h"
#include "nsGlobalWindowInner.h"
#include "nsICookiePermission.h"
#include "nsICookieService.h"
#include "nsIPermissionManager.h"
#include "nsIPrincipal.h"
#include "nsIURI.h"
#include "nsPIDOMWindow.h"
#include "nsScriptSecurityManager.h"
#include "prtime.h"
#define ANTITRACKING_PERM_KEY "3rdPartyStorage"
@ -71,6 +74,43 @@ CreatePermissionKey(const nsCString& aTrackingOrigin,
aGrantedOrigin.get());
}
// This internal method returns ACCESS_DENY if the access is denied,
// ACCESS_DEFAULT if unknown, some other access code if granted.
nsCookieAccess
CheckCookiePermissionForPrincipal(nsIPrincipal* aPrincipal)
{
nsCookieAccess access = nsICookiePermission::ACCESS_DEFAULT;
if (!aPrincipal->GetIsCodebasePrincipal()) {
return access;
}
nsCOMPtr<nsICookiePermission> cps =
do_GetService(NS_COOKIEPERMISSION_CONTRACTID);
if (NS_WARN_IF(!cps)) {
return access;
}
nsresult rv = cps->CanAccess(aPrincipal, &access);
if (NS_WARN_IF(NS_FAILED(rv))) {
return access;
}
// If we have a custom cookie permission, let's use it.
return access;
}
int32_t
CookiesBehavior(nsIPrincipal* aPrincipal)
{
// WebExtensions principals always get BEHAVIOR_ACCEPT as cookieBehavior
// (See Bug 1406675 for rationale).
if (BasePrincipal::Cast(aPrincipal)->AddonPolicy()) {
return nsICookieService::BEHAVIOR_ACCEPT;
}
return StaticPrefs::network_cookie_cookieBehavior();
}
} // anonymous
/* static */ RefPtr<AntiTrackingCommon::StorageAccessGrantPromise>
@ -79,7 +119,8 @@ AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(const nsAString& aOrigi
{
MOZ_ASSERT(aParentWindow);
if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) {
if (StaticPrefs::network_cookie_cookieBehavior() !=
nsICookieService::BEHAVIOR_REJECT_TRACKER) {
return StorageAccessGrantPromise::CreateAndResolve(true, __func__);
}
@ -175,25 +216,60 @@ AntiTrackingCommon::SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(n
}
bool
AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsPIDOMWindowInner* a3rdPartyTrackingWindow,
AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsPIDOMWindowInner* aWindow,
nsIURI* aURI)
{
MOZ_ASSERT(a3rdPartyTrackingWindow);
MOZ_ASSERT(aWindow);
MOZ_ASSERT(aURI);
if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) {
nsGlobalWindowInner* innerWindow = nsGlobalWindowInner::Cast(aWindow);
nsIPrincipal* toplevelPrincipal = innerWindow->GetTopLevelPrincipal();
if (!toplevelPrincipal) {
// We are already the top-level principal. Let's use the window's principal.
toplevelPrincipal = innerWindow->GetPrincipal();
}
if (!toplevelPrincipal) {
// This should not be possible, right?
return false;
}
nsCookieAccess access = CheckCookiePermissionForPrincipal(toplevelPrincipal);
if (access != nsICookiePermission::ACCESS_DEFAULT) {
return access != nsICookiePermission::ACCESS_DENY;
}
int32_t behavior = CookiesBehavior(toplevelPrincipal);
if (behavior == nsICookieService::BEHAVIOR_ACCEPT) {
return true;
}
if (!nsContentUtils::IsThirdPartyWindowOrChannel(a3rdPartyTrackingWindow,
nullptr, aURI) ||
!nsContentUtils::IsTrackingResourceWindow(a3rdPartyTrackingWindow)) {
if (behavior == nsICookieService::BEHAVIOR_REJECT) {
return false;
}
// Let's check if this is a 3rd party context.
if (!nsContentUtils::IsThirdPartyWindowOrChannel(aWindow, nullptr, aURI)) {
return true;
}
if (behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN ||
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.
return false;
}
MOZ_ASSERT(behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER);
if (!nsContentUtils::IsTrackingResourceWindow(aWindow)) {
return true;
}
nsCOMPtr<nsIPrincipal> parentPrincipal;
nsAutoCString trackingOrigin;
if (!GetParentPrincipalAndTrackingOrigin(nsGlobalWindowInner::Cast(a3rdPartyTrackingWindow),
if (!GetParentPrincipalAndTrackingOrigin(nsGlobalWindowInner::Cast(aWindow),
getter_AddRefs(parentPrincipal),
trackingOrigin)) {
return false;
@ -228,13 +304,90 @@ AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsIHttpChannel* aChannel
{
MOZ_ASSERT(aURI);
MOZ_ASSERT(aChannel);
MOZ_ASSERT(aChannel->GetIsTrackingResource());
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
if (!loadInfo) {
return true;
}
// We need to find the correct principal to check the cookie permission. For
// third-party contexts, we want to check if the top-level window has a custom
// cookie permission.
nsIPrincipal* toplevelPrincipal = loadInfo->TopLevelPrincipal();
// If this is already the top-level window, we should use the loading
// principal.
if (!toplevelPrincipal) {
toplevelPrincipal = loadInfo->LoadingPrincipal();
}
nsCOMPtr<nsIPrincipal> channelPrincipal;
nsIScriptSecurityManager* ssm = nsScriptSecurityManager::GetScriptSecurityManager();
nsresult rv = ssm->GetChannelResultPrincipal(aChannel,
getter_AddRefs(channelPrincipal));
// If we don't have a loading principal and this is a document channel, we are
// a top-level window!
if (!toplevelPrincipal) {
bool isDocument = false;
nsresult rv2 = aChannel->GetIsMainDocumentChannel(&isDocument);
if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(rv2) && isDocument) {
toplevelPrincipal = channelPrincipal;
}
}
// Let's use the triggering principal then.
if (!toplevelPrincipal) {
toplevelPrincipal = loadInfo->TriggeringPrincipal();
}
if (NS_WARN_IF(!toplevelPrincipal)) {
return false;
}
nsCookieAccess access = CheckCookiePermissionForPrincipal(toplevelPrincipal);
if (access != nsICookiePermission::ACCESS_DEFAULT) {
return access != nsICookiePermission::ACCESS_DENY;
}
if (NS_WARN_IF(NS_FAILED(rv) || !channelPrincipal)) {
return false;
}
int32_t behavior = CookiesBehavior(channelPrincipal);
if (behavior == nsICookieService::BEHAVIOR_ACCEPT) {
return true;
}
if (behavior == nsICookieService::BEHAVIOR_REJECT) {
return false;
}
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = services::GetThirdPartyUtil();
if (!thirdPartyUtil) {
return true;
}
bool thirdParty = false;
Unused << thirdPartyUtil->IsThirdPartyChannel(aChannel,
nullptr,
&thirdParty);
// Grant if it's not a 3rd party.
if (!thirdParty) {
return true;
}
if (behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN ||
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.
return false;
}
MOZ_ASSERT(behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER);
nsIPrincipal* parentPrincipal = loadInfo->TopLevelStorageAreaPrincipal();
if (!parentPrincipal) {
// parentPrincipal can be null if the parent window is not the top-level
@ -250,8 +403,15 @@ AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsIHttpChannel* aChannel
}
}
// Not a tracker.
if (!aChannel->GetIsTrackingResource()) {
return true;
}
// Let's see if we have to grant the access for this particular channel.
nsCOMPtr<nsIURI> trackingURI;
nsresult rv = aChannel->GetURI(getter_AddRefs(trackingURI));
rv = aChannel->GetURI(getter_AddRefs(trackingURI));
if (NS_WARN_IF(NS_FAILED(rv))) {
return true;
}
@ -286,6 +446,20 @@ AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsIHttpChannel* aChannel
return result == nsIPermissionManager::ALLOW_ACTION;
}
bool
AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsIPrincipal* aPrincipal)
{
MOZ_ASSERT(aPrincipal);
nsCookieAccess access = CheckCookiePermissionForPrincipal(aPrincipal);
if (access != nsICookiePermission::ACCESS_DEFAULT) {
return access != nsICookiePermission::ACCESS_DENY;
}
int32_t behavior = CookiesBehavior(aPrincipal);
return behavior != nsICookieService::BEHAVIOR_REJECT;
}
/* static */ bool
AntiTrackingCommon::MaybeIsFirstPartyStorageAccessGrantedFor(nsPIDOMWindowInner* aFirstPartyWindow,
nsIURI* aURI)
@ -294,7 +468,8 @@ AntiTrackingCommon::MaybeIsFirstPartyStorageAccessGrantedFor(nsPIDOMWindowInner*
MOZ_ASSERT(!nsContentUtils::IsTrackingResourceWindow(aFirstPartyWindow));
MOZ_ASSERT(aURI);
if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) {
if (StaticPrefs::network_cookie_cookieBehavior() !=
nsICookieService::BEHAVIOR_REJECT_TRACKER) {
return true;
}
@ -309,6 +484,11 @@ AntiTrackingCommon::MaybeIsFirstPartyStorageAccessGrantedFor(nsPIDOMWindowInner*
return false;
}
nsCookieAccess access = CheckCookiePermissionForPrincipal(parentPrincipal);
if (access != nsICookiePermission::ACCESS_DEFAULT) {
return access != nsICookiePermission::ACCESS_DENY;
}
nsAutoString origin;
nsresult rv = nsContentUtils::GetUTFOrigin(aURI, origin);
if (NS_WARN_IF(NS_FAILED(rv))) {

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

@ -46,12 +46,15 @@ public:
MaybeIsFirstPartyStorageAccessGrantedFor(nsPIDOMWindowInner* aFirstPartyWindow,
nsIURI* aURI);
// This can be called only if the a3rdPartyTrackingChannel is _really_ a 3rd
// party context and marked as tracking resource.
// It returns true if the URI has access to the first party storage.
// aChannel can be a 3rd party channel, or not.
static bool
IsFirstPartyStorageAccessGrantedFor(nsIHttpChannel* a3rdPartyTrackingChannel,
nsIURI* aURI);
IsFirstPartyStorageAccessGrantedFor(nsIHttpChannel* aChannel, nsIURI* aURI);
// This method checks if the principal has the permission to access to the
// first party storage.
static bool
IsFirstPartyStorageAccessGrantedFor(nsIPrincipal* aPrincipal);
// Grant the permission for aOrigin to have access to the first party storage.
// This method can handle 2 different scenarios:

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

@ -5,7 +5,7 @@ add_task(async function() {
await SpecialPowers.flushPrefEnv();
await SpecialPowers.pushPrefEnv({"set": [
["privacy.restrict3rdpartystorage.enabled", true],
["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER],
["privacy.trackingprotection.enabled", false],
["privacy.trackingprotection.pbmode.enabled", false],
["privacy.trackingprotection.annotate_channels", true],

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

@ -5,7 +5,7 @@ add_task(async function() {
await SpecialPowers.flushPrefEnv();
await SpecialPowers.pushPrefEnv({"set": [
["privacy.restrict3rdpartystorage.enabled", true],
["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER],
["privacy.trackingprotection.enabled", false],
["privacy.trackingprotection.pbmode.enabled", false],
["privacy.trackingprotection.annotate_channels", true],

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

@ -39,7 +39,7 @@ this.AntiTracking = {
async _setupTest(blocking, extraPrefs) {
await SpecialPowers.flushPrefEnv();
await SpecialPowers.pushPrefEnv({"set": [
["privacy.restrict3rdpartystorage.enabled", blocking],
["network.cookie.cookieBehavior", blocking ? Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER : Ci.nsICookieService.BEHAVIOR_ACCEPT],
["privacy.trackingprotection.enabled", false],
["privacy.trackingprotection.pbmode.enabled", false],
["privacy.trackingprotection.annotate_channels", blocking],