Bug 1603969 - Part 1: Remove the concept of granted origins from the anti-tracking backend; r=baku

Granted origins cause a third-party tracker browsing context to not get
full first-party storage access after successfully calling the storage
access API or a heuristic granting ephemeral access.

For example, after https://tracker.example calls the storage access API
successfully in the third-party context, they embed
https://other-tracker.example, and that load fails because of ETP
restrictions.  Here what happens is that https://other-tracker.example
is mistakenly considered the granted origin, and because such a
permission doesn't exist, access is denied.

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Ehsan Akhgari 2019-12-19 02:56:52 +00:00
parent 066888a1e5
commit 1ca91dd7ab
9 changed files with 46 additions and 156 deletions

View File

@ -779,10 +779,7 @@ var ThirdPartyCookies = {
for (let perm of Services.perms.getAllForPrincipal(
gBrowser.contentPrincipal
)) {
if (
perm.type == "3rdPartyStorage^" + origin ||
perm.type.startsWith("3rdPartyStorage^" + origin + "^")
) {
if (perm.type == "3rdPartyStorage^" + origin) {
return perm.capability;
}
}
@ -799,10 +796,7 @@ var ThirdPartyCookies = {
for (let perm of Services.perms.getAllForPrincipal(
gBrowser.contentPrincipal
)) {
if (
perm.type == "3rdPartyStorage^" + origin ||
perm.type.startsWith("3rdPartyStorage^" + origin + "^")
) {
if (perm.type == "3rdPartyStorage^" + origin) {
Services.perms.removePermission(perm);
}
}

View File

@ -5787,13 +5787,11 @@ mozilla::ipc::IPCResult ContentParent::RecvAutomaticStorageAccessCanBeGranted(
mozilla::ipc::IPCResult
ContentParent::RecvFirstPartyStorageAccessGrantedForOrigin(
const Principal& aParentPrincipal, const Principal& aTrackingPrincipal,
const nsCString& aTrackingOrigin, const nsCString& aGrantedOrigin,
const int& aAllowMode,
const nsCString& aTrackingOrigin, const int& aAllowMode,
FirstPartyStorageAccessGrantedForOriginResolver&& aResolver) {
AntiTrackingCommon::
SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(
aParentPrincipal, aTrackingPrincipal, aTrackingOrigin, aGrantedOrigin,
aAllowMode)
aParentPrincipal, aTrackingPrincipal, aTrackingOrigin, aAllowMode)
->Then(GetCurrentThreadSerialEventTarget(), __func__,
[aResolver = std::move(aResolver)](
AntiTrackingCommon::FirstPartyStorageAccessGrantPromise::

View File

@ -1198,8 +1198,7 @@ class ContentParent final
mozilla::ipc::IPCResult RecvFirstPartyStorageAccessGrantedForOrigin(
const Principal& aParentPrincipal, const Principal& aTrackingPrincipal,
const nsCString& aTrackingOrigin, const nsCString& aGrantedOrigin,
const int& aAllowMode,
const nsCString& aTrackingOrigin, const int& aAllowMode,
FirstPartyStorageAccessGrantedForOriginResolver&& aResolver);
mozilla::ipc::IPCResult RecvStoreUserInteractionAsPermission(

View File

@ -1490,7 +1490,6 @@ parent:
async FirstPartyStorageAccessGrantedForOrigin(Principal aParentPrincipal,
Principal aTrackingPrincipal,
nsCString aTrackingOrigin,
nsCString aGrantedOrigin,
int aAllowMode)
returns (bool unused);

View File

@ -44,11 +44,7 @@ CookieBlockedTracker=Request to access cookie or storage on “%1$S” was block
CookieBlockedAll=Request to access cookie or storage on “%1$S” was blocked because we are blocking all storage access requests.
CookieBlockedForeign=Request to access cookie or storage on “%1$S” was blocked because we are blocking all third-party storage access requests and content blocking is enabled.
# LOCALIZATION NOTE (CookieAllowedForOriginOnTrackerByStorageAccessAPI): %3$S, %2$S and %1$S are URLs.
CookieAllowedForOriginOnTrackerByStorageAccessAPI=Storage access granted for “%3$S” opened by tracker “%2$S” on “%1$S”.
# LOCALIZATION NOTE (CookieAllowedForTrackerByStorageAccessAPI): %2$S and %1$S are URLs.
CookieAllowedForTrackerByStorageAccessAPI=Storage access granted for tracker “%2$S” on “%1$S”.
# LOCALIZATION NOTE (CookieAllowedForOriginOnTrackerByHeuristic): %3$S, %2$S and %1$S are URLs.
CookieAllowedForOriginOnTrackerByHeuristic=Storage access automatically granted for “%3$S” opened by tracker “%2$S” on “%1$S”.
# LOCALIZATION NOTE (CookieAllowedForTrackerByHeuristic): %2$S and %1$S are URLs.
CookieAllowedForTrackerByHeuristic=Storage access automatically granted for tracker “%2$S” on “%1$S”.

View File

@ -128,27 +128,6 @@ void CreatePermissionKey(const nsCString& aTrackingOrigin,
aPermissionKey.Append(aTrackingOrigin);
}
void CreatePermissionKey(const nsCString& aTrackingOrigin,
const nsCString& aGrantedOrigin,
nsACString& aPermissionKey) {
MOZ_ASSERT(aPermissionKey.IsEmpty());
if (aTrackingOrigin == aGrantedOrigin) {
CreatePermissionKey(aTrackingOrigin, aPermissionKey);
return;
}
static const nsLiteralCString prefix =
NS_LITERAL_CSTRING(ANTITRACKING_PERM_KEY "^");
aPermissionKey.SetCapacity(prefix.Length() + 1 + aTrackingOrigin.Length() +
aGrantedOrigin.Length());
aPermissionKey.Append(prefix);
aPermissionKey.Append(aTrackingOrigin);
aPermissionKey.AppendLiteral("^");
aPermissionKey.Append(aGrantedOrigin);
}
// This internal method returns ACCESS_DENY if the access is denied,
// ACCESS_DEFAULT if unknown, some other access code if granted.
uint32_t CheckCookiePermissionForPrincipal(nsICookieSettings* aCookieSettings,
@ -464,7 +443,6 @@ void ReportBlockingToConsole(nsPIDOMWindowOuter* aWindow, nsIURI* aURI,
void ReportUnblockingToConsole(
nsPIDOMWindowInner* aWindow, const nsAString& aTrackingOrigin,
const nsAString& aGrantedOrigin,
AntiTrackingCommon::StorageAccessGrantedReason aReason) {
nsCOMPtr<nsIPrincipal> principal =
nsGlobalWindowInner::Cast(aWindow)->GetPrincipal();
@ -478,7 +456,6 @@ void ReportUnblockingToConsole(
}
nsAutoString trackingOrigin(aTrackingOrigin);
nsAutoString grantedOrigin(aGrantedOrigin);
nsAutoString sourceLine;
uint32_t lineNumber = 0, columnNumber = 0;
@ -489,8 +466,8 @@ void ReportUnblockingToConsole(
RefPtr<Runnable> runnable = NS_NewRunnableFunction(
"ReportUnblockingToConsoleDelayed",
[doc, principal, trackingOrigin, grantedOrigin, sourceLine, lineNumber,
columnNumber, aReason]() {
[doc, principal, trackingOrigin, sourceLine, lineNumber, columnNumber,
aReason]() {
nsAutoString origin;
nsresult rv = nsContentUtils::GetUTFOrigin(principal, origin);
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -499,39 +476,24 @@ void ReportUnblockingToConsole(
// Not adding grantedOrigin yet because we may not want it later.
AutoTArray<nsString, 3> params = {origin, trackingOrigin};
const char* messageWithDifferentOrigin = nullptr;
const char* messageWithSameOrigin = nullptr;
switch (aReason) {
case AntiTrackingCommon::eStorageAccessAPI:
messageWithDifferentOrigin =
"CookieAllowedForOriginOnTrackerByStorageAccessAPI";
messageWithSameOrigin = "CookieAllowedForTrackerByStorageAccessAPI";
break;
case AntiTrackingCommon::eOpenerAfterUserInteraction:
MOZ_FALLTHROUGH;
case AntiTrackingCommon::eOpener:
messageWithDifferentOrigin =
"CookieAllowedForOriginOnTrackerByHeuristic";
messageWithSameOrigin = "CookieAllowedForTrackerByHeuristic";
break;
}
if (trackingOrigin == grantedOrigin) {
nsContentUtils::ReportToConsole(
nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("Content Blocking"), doc,
nsContentUtils::eNECKO_PROPERTIES, messageWithSameOrigin, params,
nullptr, sourceLine, lineNumber, columnNumber);
} else {
params.AppendElement(grantedOrigin);
nsContentUtils::ReportToConsole(
nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("Content Blocking"), doc,
nsContentUtils::eNECKO_PROPERTIES, messageWithDifferentOrigin,
params, nullptr, sourceLine, lineNumber, columnNumber);
}
nsContentUtils::ReportToConsole(
nsIScriptError::warningFlag, NS_LITERAL_CSTRING("Content Blocking"),
doc, nsContentUtils::eNECKO_PROPERTIES, messageWithSameOrigin,
params, nullptr, sourceLine, lineNumber, columnNumber);
});
RunConsoleReportingRunnable(runnable.forget());
@ -943,16 +905,13 @@ AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(
return StorageAccessGrantPromise::CreateAndReject(false, __func__);
}
nsAutoCString origin;
nsresult rv = nsContentUtils::GetASCIIOrigin(uri, origin);
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Can't get the origin from the URI"));
return StorageAccessGrantPromise::CreateAndReject(false, __func__);
if (MOZ_LOG_TEST(gAntiTrackingLog, mozilla::LogLevel::Debug)) {
nsAutoCString origin;
Unused << nsContentUtils::GetASCIIOrigin(uri, origin);
LOG(("Adding a first-party storage exception for %s...",
PromiseFlatCString(origin).get()));
}
LOG(("Adding a first-party storage exception for %s...",
PromiseFlatCString(origin).get()));
Document* parentDoc = aParentWindow->GetExtantDoc();
if (!parentDoc) {
LOG(("Parent window has no doc"));
@ -996,6 +955,13 @@ AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(
// We are a first party resource.
if (outerParentWindow->IsTopLevelWindow()) {
nsAutoCString origin;
nsresult rv = nsContentUtils::GetASCIIOrigin(uri, origin);
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Can't get the origin from the URI"));
return StorageAccessGrantPromise::CreateAndReject(false, __func__);
}
trackingOrigin = origin;
trackingPrincipal = aPrincipal;
rv = trackingPrincipal->GetURI(getter_AddRefs(trackingURI));
@ -1098,11 +1064,11 @@ AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(
}
auto storePermission =
[pwin, parentWindow, origin, trackingOrigin, trackingPrincipal,
trackingURI, topInnerWindow, topLevelStoragePrincipal,
[pwin, parentWindow, trackingOrigin, trackingPrincipal, trackingURI,
topInnerWindow, topLevelStoragePrincipal,
aReason](int aAllowMode) -> RefPtr<StorageAccessGrantPromise> {
nsAutoCString permissionKey;
CreatePermissionKey(trackingOrigin, origin, permissionKey);
CreatePermissionKey(trackingOrigin, permissionKey);
// Let's store the permission in the current parent window.
topInnerWindow->SaveStorageAccessGranted(permissionKey);
@ -1118,16 +1084,14 @@ AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(
Some(aReason));
ReportUnblockingToConsole(parentWindow,
NS_ConvertUTF8toUTF16(trackingOrigin),
NS_ConvertUTF8toUTF16(origin), aReason);
NS_ConvertUTF8toUTF16(trackingOrigin), aReason);
if (XRE_IsParentProcess()) {
LOG(("Saving the permission: trackingOrigin=%s, grantedOrigin=%s",
trackingOrigin.get(), origin.get()));
LOG(("Saving the permission: trackingOrigin=%s", trackingOrigin.get()));
return SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(
topLevelStoragePrincipal, trackingPrincipal, trackingOrigin,
origin, aAllowMode)
aAllowMode)
->Then(GetCurrentThreadSerialEventTarget(), __func__,
[](FirstPartyStorageAccessGrantPromise::ResolveOrRejectValue&&
aValue) {
@ -1145,16 +1109,15 @@ AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(
LOG(
("Asking the parent process to save the permission for us: "
"trackingOrigin=%s, grantedOrigin=%s",
trackingOrigin.get(), origin.get()));
"trackingOrigin=%s",
trackingOrigin.get()));
// This is not really secure, because here we have the content process
// sending the request of storing a permission.
return cc
->SendFirstPartyStorageAccessGrantedForOrigin(
IPC::Principal(topLevelStoragePrincipal),
IPC::Principal(trackingPrincipal), trackingOrigin, origin,
aAllowMode)
IPC::Principal(trackingPrincipal), trackingOrigin, aAllowMode)
->Then(GetCurrentThreadSerialEventTarget(), __func__,
[](const ContentChild::
FirstPartyStorageAccessGrantedForOriginPromise::
@ -1186,8 +1149,7 @@ AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(
RefPtr<mozilla::AntiTrackingCommon::FirstPartyStorageAccessGrantPromise>
AntiTrackingCommon::SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(
nsIPrincipal* aParentPrincipal, nsIPrincipal* aTrackingPrincipal,
const nsCString& aTrackingOrigin, const nsCString& aGrantedOrigin,
int aAllowMode) {
const nsCString& aTrackingOrigin, int aAllowMode) {
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(aAllowMode == eAllow || aAllowMode == eAllowAutoGrant);
@ -1200,8 +1162,8 @@ AntiTrackingCommon::SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(
nsCOMPtr<nsIURI> parentPrincipalURI;
Unused << aParentPrincipal->GetURI(getter_AddRefs(parentPrincipalURI));
LOG_SPEC(("Saving a first-party storage permission on %s for "
"trackingOrigin=%s grantedOrigin=%s",
_spec, aTrackingOrigin.get(), aGrantedOrigin.get()),
"trackingOrigin=%s",
_spec, aTrackingOrigin.get()),
parentPrincipalURI);
if (NS_WARN_IF(!aParentPrincipal)) {
@ -1236,7 +1198,7 @@ AntiTrackingCommon::SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(
}
nsAutoCString type;
CreatePermissionKey(aTrackingOrigin, aGrantedOrigin, type);
CreatePermissionKey(aTrackingOrigin, type);
LOG(
("Computed permission key: %s, expiry: %u, proceeding to save in the "
@ -1499,15 +1461,8 @@ bool AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(
}
Unused << parentPrincipal->GetURI(getter_AddRefs(parentPrincipalURI));
nsAutoCString grantedOrigin;
nsresult rv = nsContentUtils::GetASCIIOrigin(aURI, grantedOrigin);
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG_SPEC(("Failed to compute the origin from %s", _spec), aURI);
return false;
}
nsAutoCString type;
CreatePermissionKey(trackingOrigin, grantedOrigin, type);
CreatePermissionKey(trackingOrigin, type);
if (topInnerWindow->HasStorageAccessGranted(type)) {
LOG(("Permission stored in the window. All good."));
@ -1773,15 +1728,8 @@ bool AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(
return false;
}
nsAutoCString origin;
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;
}
nsAutoCString type;
CreatePermissionKey(trackingOrigin, origin, type);
CreatePermissionKey(trackingOrigin, type);
uint32_t privateBrowsingId = 0;
rv = channelPrincipal->GetPrivateBrowsingId(&privateBrowsingId);

View File

@ -130,8 +130,7 @@ class AntiTrackingCommon final {
static RefPtr<FirstPartyStorageAccessGrantPromise>
SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(
nsIPrincipal* aPrincipal, nsIPrincipal* aTrackingPrinciapl,
const nsCString& aParentOrigin, const nsCString& aGrantedOrigin,
int aAllowMode);
const nsCString& aTrackingOrigin, int aAllowMode);
// Check whether a top window principal is on the content blocking allow list.
static nsresult IsOnContentBlockingAllowList(nsIPrincipal* aTopWinPrincipal,

View File

@ -879,19 +879,14 @@ const PermissionsCleaner = {
if (!toBeRemoved && perm.type.startsWith("3rdPartyStorage^")) {
let parts = perm.type.split("^");
for (let i = 1; i < parts.length; ++i) {
let uri;
try {
uri = Services.io.newURI(parts[i]);
} catch (ex) {
continue;
}
toBeRemoved = Services.eTLD.hasRootDomain(uri.host, aHost);
if (toBeRemoved) {
break;
}
let uri;
try {
uri = Services.io.newURI(parts[1]);
} catch (ex) {
continue;
}
toBeRemoved = Services.eTLD.hasRootDomain(uri.host, aHost);
}
if (!toBeRemoved) {

View File

@ -133,16 +133,6 @@ add_task(async function test_3rdpartystorage_permissions() {
"cookie",
Services.perms.ALLOW_ACTION
);
Services.perms.addFromPrincipal(
oneMorePrincipal,
"3rdPartyStorage^https://example.net^https://example.org",
Services.perms.ALLOW_ACTION
);
Services.perms.addFromPrincipal(
oneMorePrincipal,
"3rdPartyStorage^https://example.org^https://example.net",
Services.perms.ALLOW_ACTION
);
Assert.ok(
Services.perms.getPermissionObject(principal, "cookie", true) != null
@ -160,20 +150,6 @@ add_task(async function test_3rdpartystorage_permissions() {
Assert.ok(
Services.perms.getPermissionObject(oneMorePrincipal, "cookie", true) != null
);
Assert.ok(
Services.perms.getPermissionObject(
oneMorePrincipal,
"3rdPartyStorage^https://example.net^https://example.org",
true
) != null
);
Assert.ok(
Services.perms.getPermissionObject(
oneMorePrincipal,
"3rdPartyStorage^https://example.org^https://example.net",
true
) != null
);
await new Promise(aResolve => {
Services.clearData.deleteDataFromPrincipal(
@ -203,20 +179,6 @@ add_task(async function test_3rdpartystorage_permissions() {
Assert.ok(
Services.perms.getPermissionObject(oneMorePrincipal, "cookie", true) != null
);
Assert.ok(
Services.perms.getPermissionObject(
oneMorePrincipal,
"3rdPartyStorage^https://example.net^https://example.org",
true
) == null
);
Assert.ok(
Services.perms.getPermissionObject(
oneMorePrincipal,
"3rdPartyStorage^https://example.org^https://example.net",
true
) == null
);
await new Promise(aResolve => {
Services.clearData.deleteData(