зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1876504 - Also allow a same-origin initiated iframe to get storage access from its parent - r=anti-tracking-reviewers,timhuang
Differential Revision: https://phabricator.services.mozilla.com/D203313
This commit is contained in:
Родитель
271aab4b32
Коммит
d0f8a1c146
|
@ -287,6 +287,13 @@ async function MaybeSetStorageAccess(origin, embedding_origin, value) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// Navigate the inner iframe using the given frame.
|
||||
function NavigateChild(frame, url) {
|
||||
return PostMessageAndAwaitReply(
|
||||
{ command: "navigate_child", url }, frame.contentWindow);
|
||||
}
|
||||
|
||||
// Starts a dedicated worker in the given frame.
|
||||
function StartDedicatedWorker(frame) {
|
||||
return PostMessageAndAwaitReply(
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
// META: script=helpers.js
|
||||
// META: script=/cookies/resources/cookie-helper.sub.js
|
||||
// META: script=/resources/testdriver.js
|
||||
// META: script=/resources/testdriver-vendor.js
|
||||
'use strict';
|
||||
|
||||
(async function() {
|
||||
// This is cross-domain from the current document.
|
||||
const altWww = "https://{{hosts[alt][www]}}:{{ports[https][0]}}";
|
||||
const altRoot = "https://{{hosts[alt][]}}:{{ports[https][0]}}";
|
||||
const responderPath = "/storage-access-api/resources/script-with-cookie-header.py?script=embedded_responder.js";
|
||||
const forwarderPath = "/storage-access-api/resources/script-with-cookie-header.py?script=embedded_forwarder.js";
|
||||
|
||||
const altWwwResponder = `${altWww}${responderPath}`;
|
||||
const altRootResponder = `${altRoot}${responderPath}`;
|
||||
const altWwwNestedCrossOriginResponder = `${altRoot}${forwarderPath}&inner_url=${encodeURI(altWwwResponder)}`;
|
||||
|
||||
async function SetUpResponderFrame(t, url) {
|
||||
const frame = await CreateFrame(url);
|
||||
|
||||
await SetPermissionInFrame(frame, [{ name: 'storage-access' }, 'granted']);
|
||||
t.add_cleanup(async () => {
|
||||
await test_driver.delete_all_cookies();
|
||||
await SetPermissionInFrame(frame, [{ name: 'storage-access' }, 'prompt']);
|
||||
await MaybeSetStorageAccess("*", "*", "allowed");
|
||||
});
|
||||
|
||||
assert_false(await FrameHasStorageAccess(frame), "frame initially does not have storage access.");
|
||||
assert_false(await HasUnpartitionedCookie(frame), "frame initially does not have access to cookies.");
|
||||
|
||||
assert_true(await RequestStorageAccessInFrame(frame), "requestStorageAccess resolves without requiring a gesture.");
|
||||
|
||||
assert_true(await FrameHasStorageAccess(frame), "frame has storage access after request.");
|
||||
assert_true(await HasUnpartitionedCookie(frame), "frame has access to cookies after request.");
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
promise_test(async (t) => {
|
||||
await MaybeSetStorageAccess("*", "*", "blocked");
|
||||
await SetFirstPartyCookieAndUnsetStorageAccessPermission(altWww);
|
||||
|
||||
const frame = await SetUpResponderFrame(t, altWwwNestedCrossOriginResponder);
|
||||
|
||||
await NavigateChild(frame, altWwwResponder);
|
||||
|
||||
assert_true(await FrameHasStorageAccess(frame), "innermost frame has storage access after refresh.");
|
||||
assert_true(await HasUnpartitionedCookie(frame), "innermost frame has access to cookies after refresh.");
|
||||
}, "Same-site-initiated same-origin navigations preserve storage access");
|
||||
|
||||
promise_test(async (t) => {
|
||||
await MaybeSetStorageAccess("*", "*", "blocked");
|
||||
await SetFirstPartyCookieAndUnsetStorageAccessPermission(altWww);
|
||||
|
||||
const frame = await SetUpResponderFrame(t, altWwwNestedCrossOriginResponder);
|
||||
|
||||
await NavigateChild(frame, altRootResponder);
|
||||
|
||||
assert_false(await FrameHasStorageAccess(frame), "innermost frame has no storage access after refresh.");
|
||||
assert_false(await HasUnpartitionedCookie(frame), "innermost frame has no access to cookies after refresh.");
|
||||
let cookieOnLoad = await GetHTTPCookiesFromFrame(frame);
|
||||
assert_false(cookieStringHasCookie("cookie", "unpartitioned", cookieOnLoad), "innermost frame has cookie in initial load");
|
||||
}, "Same-site-initiated cross-origin navigations do not preserve storage access");
|
||||
|
||||
})();
|
|
@ -0,0 +1,50 @@
|
|||
"use strict";
|
||||
|
||||
test_driver.set_test_context(window.top);
|
||||
|
||||
function waitForMessage(timestamp) {
|
||||
return new Promise(resolve => {
|
||||
const listener = (event) => {
|
||||
if (!timestamp || event.data.timestamp == timestamp) {
|
||||
window.removeEventListener("message", listener);
|
||||
resolve(event.data);
|
||||
}
|
||||
};
|
||||
window.addEventListener("message", listener);
|
||||
});
|
||||
}
|
||||
|
||||
var iframe = document.createElement('iframe');
|
||||
const queryString = window.location.search;
|
||||
const urlParams = new URLSearchParams(queryString);
|
||||
iframe.src = urlParams.get("inner_url");
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
window.addEventListener("message", async (event) => {
|
||||
function replyToParent(data) {
|
||||
parent.postMessage(
|
||||
{timestamp: event.data.timestamp, data}, "*");
|
||||
}
|
||||
|
||||
if (!event.data["command"]) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event.data["command"]) {
|
||||
case "navigate_child":
|
||||
iframe.onload = () => replyToParent(event.data.url);
|
||||
iframe.src = event.data.url;
|
||||
break;
|
||||
case "reload":
|
||||
case "navigate":
|
||||
iframe.contentWindow.postMessage({timestamp, ...event.data}, "*");
|
||||
break;
|
||||
default:{
|
||||
const timestamp = event.data.timestamp;
|
||||
const p = waitForMessage(timestamp);
|
||||
iframe.contentWindow.postMessage({timestamp, ...event.data}, "*");
|
||||
replyToParent(await p.then(resp => resp.data));
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
|
@ -31,7 +31,7 @@ function connectAndGetRequestCookiesFrom(origin) {
|
|||
window.addEventListener("message", async (event) => {
|
||||
function reply(data) {
|
||||
event.source.postMessage(
|
||||
{timestamp: event.data.timestamp, data}, event.origin);
|
||||
{timestamp: event.data.timestamp, data}, "*");
|
||||
}
|
||||
|
||||
switch (event.data["command"]) {
|
||||
|
|
|
@ -13,7 +13,10 @@ def main(request, response):
|
|||
var httpCookies = "%s";
|
||||
</script>
|
||||
|
||||
<body>
|
||||
<script src="%s"></script>
|
||||
</body>
|
||||
|
||||
""" % (cookie_header, script)
|
||||
|
||||
return (200, [], body)
|
||||
|
|
|
@ -567,9 +567,8 @@ AntiTrackingUtils::GetStoragePermissionStateInParent(nsIChannel* aChannel) {
|
|||
|
||||
if (policyType == ExtContentPolicy::TYPE_SUBDOCUMENT) {
|
||||
// For loads of framed documents, we only use storage access
|
||||
// if the load is the result of a same-origin, self-initiated
|
||||
// if the load is the result of a same-origin, same-site-initiated
|
||||
// navigation of the frame.
|
||||
uint64_t targetWindowIdNoTop = bc->GetCurrentInnerWindowId();
|
||||
uint64_t triggeringWindowId;
|
||||
rv = loadInfo->GetTriggeringWindowId(&triggeringWindowId);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
@ -581,10 +580,29 @@ AntiTrackingUtils::GetStoragePermissionStateInParent(nsIChannel* aChannel) {
|
|||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nsILoadInfo::NoStoragePermission;
|
||||
}
|
||||
RefPtr<net::HttpBaseChannel> httpChannel = do_QueryObject(aChannel);
|
||||
|
||||
if (targetWindowIdNoTop == triggeringWindowId &&
|
||||
triggeringWindowHasStorageAccess &&
|
||||
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
||||
RefPtr<nsIPrincipal> channelResultPrincipal;
|
||||
rv = ssm->GetChannelResultPrincipal(aChannel,
|
||||
getter_AddRefs(channelResultPrincipal));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nsILoadInfo::NoStoragePermission;
|
||||
}
|
||||
RefPtr<net::HttpBaseChannel> httpChannel = do_QueryObject(aChannel);
|
||||
bool crossSiteInitiated = false;
|
||||
if (bc && bc->GetParent()->GetCurrentWindowContext()) {
|
||||
RefPtr<WindowGlobalParent> triggeringWGP =
|
||||
WindowGlobalParent::GetByInnerWindowId(triggeringWindowId);
|
||||
if (triggeringWGP && triggeringWGP->DocumentPrincipal()) {
|
||||
rv = triggeringWGP->DocumentPrincipal()->IsThirdPartyPrincipal(
|
||||
channelResultPrincipal, &crossSiteInitiated);
|
||||
if (NS_FAILED(rv)) {
|
||||
crossSiteInitiated = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!crossSiteInitiated && triggeringWindowHasStorageAccess &&
|
||||
trackingPrincipal->Equals(framePrincipal) && httpChannel &&
|
||||
!httpChannel->HasRedirectTaintedOrigin()) {
|
||||
return nsILoadInfo::HasStoragePermission;
|
||||
|
|
Загрузка…
Ссылка в новой задаче