Bug 1536411 - StoragePrincipal - part 6 - Cookies, r=Ehsan

Differential Revision: https://phabricator.services.mozilla.com/D24864

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Andrea Marchesini 2019-04-11 16:28:51 +00:00
Родитель 7524dcd07e
Коммит 0830861f7e
13 изменённых файлов: 179 добавлений и 46 удалений

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

@ -1030,7 +1030,14 @@ void nsHTMLDocument::GetCookie(nsAString& aCookie, ErrorResult& rv) {
return;
}
if (nsContentUtils::StorageDisabledByAntiTracking(this, nullptr)) {
nsContentUtils::StorageAccess storageAccess =
nsContentUtils::StorageAllowedForDocument(this);
if (storageAccess == nsContentUtils::StorageAccess::eDeny) {
return;
}
if (storageAccess == nsContentUtils::StorageAccess::ePartitionedOrDeny &&
!StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
return;
}
@ -1083,7 +1090,14 @@ void nsHTMLDocument::SetCookie(const nsAString& aCookie, ErrorResult& rv) {
return;
}
if (nsContentUtils::StorageDisabledByAntiTracking(this, nullptr)) {
nsContentUtils::StorageAccess storageAccess =
nsContentUtils::StorageAllowedForDocument(this);
if (storageAccess == nsContentUtils::StorageAccess::eDeny) {
return;
}
if (storageAccess == nsContentUtils::StorageAccess::ePartitionedOrDeny &&
!StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
return;
}

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

@ -16,6 +16,7 @@
#include "mozilla/LoadInfo.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/Monitor.h"
#include "mozilla/StoragePrincipalHelper.h"
#include "mozilla/TaskQueue.h"
#include "mozilla/Telemetry.h"
#include "nsCategoryCache.h"
@ -1851,13 +1852,14 @@ nsresult NS_LoadPersistentPropertiesFromURISpec(
bool NS_UsePrivateBrowsing(nsIChannel *channel) {
OriginAttributes attrs;
bool result = NS_GetOriginAttributes(channel, attrs);
bool result = NS_GetOriginAttributes(channel, attrs, false);
NS_ENSURE_TRUE(result, result);
return attrs.mPrivateBrowsingId > 0;
}
bool NS_GetOriginAttributes(nsIChannel *aChannel,
mozilla::OriginAttributes &aAttributes) {
mozilla::OriginAttributes &aAttributes,
bool aUsingStoragePrincipal) {
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
loadInfo->GetOriginAttributes(&aAttributes);
@ -1873,6 +1875,10 @@ bool NS_GetOriginAttributes(nsIChannel *aChannel,
isPrivate = loadContext && loadContext->UsePrivateBrowsing();
}
aAttributes.SyncAttributesWithPrivateBrowsing(isPrivate);
if (aUsingStoragePrincipal) {
StoragePrincipalHelper::PrepareOriginAttributes(aChannel, aAttributes);
}
return true;
}

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

@ -610,9 +610,12 @@ bool NS_UsePrivateBrowsing(nsIChannel *channel);
/**
* Extract the OriginAttributes from the channel's triggering principal.
* If aUsingStoragePrincipal is set to true, the originAttributes could have
* first-party isolation domain set to the top-level URI.
*/
bool NS_GetOriginAttributes(nsIChannel *aChannel,
mozilla::OriginAttributes &aAttributes);
mozilla::OriginAttributes &aAttributes,
bool aUsingStoragePrincipal = false);
/**
* Returns true if the channel has visited any cross-origin URLs on any

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

@ -13,6 +13,7 @@
#include "mozilla/ipc/URIUtils.h"
#include "mozilla/net/NeckoChild.h"
#include "mozilla/SystemGroup.h"
#include "mozilla/StoragePrincipalHelper.h"
#include "nsCookie.h"
#include "nsCookieService.h"
#include "nsContentUtils.h"
@ -175,6 +176,7 @@ void CookieServiceChild::TrackCookieLoad(nsIChannel *aChannel) {
}
}
mozilla::OriginAttributes attrs = loadInfo->GetOriginAttributes();
StoragePrincipalHelper::PrepareOriginAttributes(aChannel, attrs);
URIParams uriParams;
SerializeURI(uri, uriParams);
bool isSafeTopLevelNav = NS_IsSafeTopLevelNav(aChannel);
@ -294,6 +296,7 @@ void CookieServiceChild::GetCookieStringFromCookieHashTable(
if (aChannel) {
loadInfo = aChannel->LoadInfo();
attrs = loadInfo->GetOriginAttributes();
StoragePrincipalHelper::PrepareOriginAttributes(aChannel, attrs);
}
nsCookieService::GetBaseDomain(TLDService, aHostURI, baseDomain,
@ -562,6 +565,7 @@ nsresult CookieServiceChild::SetCookieStringInternal(nsIURI *aHostURI,
MOZ_ASSERT(loadInfo);
attrs = loadInfo->GetOriginAttributes();
StoragePrincipalHelper::PrepareOriginAttributes(aChannel, attrs);
} else {
SerializeURI(nullptr, channelURIParams);
}
@ -573,7 +577,7 @@ nsresult CookieServiceChild::SetCookieStringInternal(nsIURI *aHostURI,
if (mIPCOpen) {
SendSetCookieString(hostURIParams, channelURIParams, optionalLoadInfoArgs,
isForeign, isTrackingResource,
firstPartyStorageAccessGranted, cookieString,
firstPartyStorageAccessGranted, attrs, cookieString,
stringServerTime, aFromHttp);
}

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

@ -9,6 +9,7 @@
#include "mozilla/BasePrincipal.h"
#include "mozilla/ipc/URIUtils.h"
#include "mozilla/StoragePrincipalHelper.h"
#include "nsArrayUtils.h"
#include "nsCookieService.h"
#include "nsIChannel.h"
@ -126,6 +127,8 @@ void CookieServiceParent::TrackCookieLoad(nsIChannel *aChannel) {
bool isSafeTopLevelNav = NS_IsSafeTopLevelNav(aChannel);
bool aIsSameSiteForeign = NS_IsSameSiteForeign(aChannel, uri);
StoragePrincipalHelper::PrepareOriginAttributes(aChannel, attrs);
// Send matching cookies to Child.
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil;
thirdPartyUtil = do_GetService(THIRDPARTYUTIL_CONTRACTID);
@ -207,8 +210,9 @@ mozilla::ipc::IPCResult CookieServiceParent::RecvSetCookieString(
const URIParams &aHost, const Maybe<URIParams> &aChannelURI,
const Maybe<LoadInfoArgs> &aLoadInfoArgs, const bool &aIsForeign,
const bool &aIsTrackingResource,
const bool &aFirstPartyStorageAccessGranted, const nsCString &aCookieString,
const nsCString &aServerTime, const bool &aFromHttp) {
const bool &aFirstPartyStorageAccessGranted, const OriginAttributes &aAttrs,
const nsCString &aCookieString, const nsCString &aServerTime,
const bool &aFromHttp) {
if (!mCookieService) return IPC_OK();
// Deserialize URI. Having a host URI is mandatory and should always be
@ -240,17 +244,12 @@ mozilla::ipc::IPCResult CookieServiceParent::RecvSetCookieString(
// NB: dummyChannel could be null if something failed in CreateDummyChannel.
nsDependentCString cookieString(aCookieString, 0);
OriginAttributes attrs;
if (loadInfo) {
attrs = loadInfo->GetOriginAttributes();
}
// We set this to true while processing this cookie update, to make sure
// we don't send it back to the same content process.
mProcessingCookie = true;
mCookieService->SetCookieStringInternal(
hostURI, aIsForeign, aIsTrackingResource, aFirstPartyStorageAccessGranted,
cookieString, aServerTime, aFromHttp, attrs, dummyChannel);
cookieString, aServerTime, aFromHttp, aAttrs, dummyChannel);
mProcessingCookie = false;
return IPC_OK();
}

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

@ -49,8 +49,8 @@ class CookieServiceParent : public PCookieServiceParent {
const Maybe<LoadInfoArgs> &aLoadInfoArgs, const bool &aIsForeign,
const bool &aIsTrackingResource,
const bool &aFirstPartyStorageAccessGranted,
const nsCString &aCookieString, const nsCString &aServerTime,
const bool &aFromHttp);
const OriginAttributes &aAttrs, const nsCString &aCookieString,
const nsCString &aServerTime, const bool &aFromHttp);
mozilla::ipc::IPCResult RecvPrepareCookieList(
const URIParams &aHost, const bool &aIsForeign,

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

@ -75,6 +75,7 @@ parent:
bool isForeign,
bool isTrackingResource,
bool firstPartyStorageAccessGranted,
OriginAttributes aStoragePrincipalAttrs,
nsCString cookieString,
nsCString serverTime,
bool aFromHttp);

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

@ -1990,7 +1990,8 @@ nsresult nsCookieService::GetCookieStringCommon(nsIURI *aHostURI,
OriginAttributes attrs;
if (aChannel) {
NS_GetOriginAttributes(aChannel, attrs);
NS_GetOriginAttributes(aChannel, attrs,
true /* considering storage principal */);
}
bool isSafeTopLevelNav = NS_IsSafeTopLevelNav(aChannel);
@ -2109,7 +2110,8 @@ nsresult nsCookieService::SetCookieStringCommon(nsIURI *aHostURI,
OriginAttributes attrs;
if (aChannel) {
NS_GetOriginAttributes(aChannel, attrs);
NS_GetOriginAttributes(aChannel, attrs,
true /* considering storage principal */);
}
nsDependentCString cookieString(aCookieHeader);
@ -4040,6 +4042,12 @@ CookieStatus nsCookieService::CheckPrefs(
if (aIsForeign && aIsTrackingResource && !aFirstPartyStorageAccessGranted &&
aCookieSettings->GetCookieBehavior() ==
nsICookieService::BEHAVIOR_REJECT_TRACKER) {
if (StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
MOZ_ASSERT(!aOriginAttrs.mFirstPartyDomain.IsEmpty(),
"We must have a StoragePrincipal here!");
return STATUS_ACCEPTED;
}
COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI,
aCookieHeader, "cookies are disabled in trackers");
*aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER;

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

@ -13,6 +13,47 @@
namespace mozilla {
namespace {
already_AddRefed<nsIURI> MaybeGetFirstPartyURI(nsIChannel* aChannel) {
MOZ_ASSERT(aChannel);
if (!StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
return nullptr;
}
// Let's use the storage principal only if we need to partition the cookie
// jar.
nsContentUtils::StorageAccess access =
nsContentUtils::StorageAllowedForChannel(aChannel);
if (access != nsContentUtils::StorageAccess::ePartitionedOrDeny) {
return nullptr;
}
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
if (!httpChannel) {
return nullptr;
}
MOZ_ASSERT(httpChannel->IsThirdPartyTrackingResource());
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
nsCOMPtr<nsIPrincipal> toplevelPrincipal = loadInfo->GetTopLevelPrincipal();
if (!toplevelPrincipal) {
return nullptr;
}
nsCOMPtr<nsIURI> principalURI;
nsresult rv = toplevelPrincipal->GetURI(getter_AddRefs(principalURI));
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
return principalURI.forget();
}
} // namespace
// static
nsresult StoragePrincipalHelper::Create(nsIChannel* aChannel,
nsIPrincipal* aPrincipal,
@ -26,37 +67,11 @@ nsresult StoragePrincipalHelper::Create(nsIChannel* aChannel,
storagePrincipal.forget(aStoragePrincipal);
});
if (!StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
nsCOMPtr<nsIURI> principalURI = MaybeGetFirstPartyURI(aChannel);
if (!principalURI) {
return NS_OK;
}
// Let's use the storage principal only if we need to partition the cookie
// jar.
nsContentUtils::StorageAccess access =
nsContentUtils::StorageAllowedForChannel(aChannel);
if (access != nsContentUtils::StorageAccess::ePartitionedOrDeny) {
return NS_OK;
}
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
if (!httpChannel) {
return NS_OK;
}
MOZ_ASSERT(httpChannel->IsThirdPartyTrackingResource());
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
nsCOMPtr<nsIPrincipal> toplevelPrincipal = loadInfo->GetTopLevelPrincipal();
if (!toplevelPrincipal) {
return NS_OK;
}
nsCOMPtr<nsIURI> principalURI;
nsresult rv = toplevelPrincipal->GetURI(getter_AddRefs(principalURI));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
scopeExit.release();
nsCOMPtr<nsIPrincipal> storagePrincipal =
@ -67,4 +82,19 @@ nsresult StoragePrincipalHelper::Create(nsIChannel* aChannel,
return NS_OK;
}
// static
nsresult StoragePrincipalHelper::PrepareOriginAttributes(
nsIChannel* aChannel, OriginAttributes& aOriginAttributes) {
MOZ_ASSERT(aChannel);
nsCOMPtr<nsIURI> principalURI = MaybeGetFirstPartyURI(aChannel);
if (!principalURI) {
return NS_OK;
}
aOriginAttributes.SetFirstPartyDomain(false, principalURI,
true /* aForced */);
return NS_OK;
}
} // namespace mozilla

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

@ -12,10 +12,15 @@ class nsIPrincipal;
namespace mozilla {
class OriginAttributes;
class StoragePrincipalHelper final {
public:
static nsresult Create(nsIChannel* aChannel, nsIPrincipal* aPrincipal,
nsIPrincipal** aStoragePrincipal);
static nsresult PrepareOriginAttributes(nsIChannel* aChannel,
OriginAttributes& aOriginAttributes);
};
} // namespace mozilla

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

@ -93,3 +93,5 @@ support-files = workerIframe.html
[browser_cookieBetweenTabs.js]
[browser_partitionedMessaging.js]
[browser_partitionedIndexedDB.js]
[browser_partitionedCookies.js]
support-files = cookies.sjs

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

@ -0,0 +1,49 @@
/* import-globals-from storageprincipal_head.js */
StoragePrincipalHelper.runTest("HTTP Cookies",
async (win3rdParty, win1stParty, allowed) => {
await win3rdParty.fetch("cookies.sjs?3rd").then(r => r.text());
await win3rdParty.fetch("cookies.sjs").then(r => r.text()).then(text => {
is(text, "cookie:foopy=3rd", "3rd party cookie set");
});
await win1stParty.fetch("cookies.sjs?first").then(r => r.text());
await win1stParty.fetch("cookies.sjs").then(r => r.text()).then(text => {
is(text, "cookie:foopy=first", "First party cookie set");
});
await win3rdParty.fetch("cookies.sjs").then(r => r.text()).then(text => {
if (allowed) {
is(text, "cookie:foopy=first", "3rd party has the first party cookie set");
} else {
is(text, "cookie:foopy=3rd", "3rd party has not the first party cookie set");
}
});
},
async _ => {
await new Promise(resolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve());
});
});
StoragePrincipalHelper.runTest("DOM Cookies",
async (win3rdParty, win1stParty, allowed) => {
win3rdParty.document.cookie = "foo=3rd";
is(win3rdParty.document.cookie, "foo=3rd", "3rd party cookie set");
win1stParty.document.cookie = "foo=first";
is(win1stParty.document.cookie, "foo=first", "First party cookie set");
if (allowed) {
is(win3rdParty.document.cookie, "foo=first", "3rd party has the first party cookie set");
} else {
is(win3rdParty.document.cookie, "foo=3rd", "3rd party has not the first party cookie set");
}
},
async _ => {
await new Promise(resolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve());
});
});

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

@ -0,0 +1,12 @@
function handleRequest(aRequest, aResponse) {
aResponse.setStatusLine(aRequest.httpVersion, 200);
let cookie = "";
if (aRequest.hasHeader("Cookie")) {
cookie = aRequest.getHeader("Cookie");
}
aResponse.write("cookie:" + cookie);
if (aRequest.queryString) {
aResponse.setHeader("Set-Cookie", "foopy=" + aRequest.queryString);
}
}