From db3f1b5878720f8713b90e623b653b18a5e0f261 Mon Sep 17 00:00:00 2001 From: hackademix Date: Sun, 30 Jan 2022 00:38:31 +0100 Subject: [PATCH] Switch contextual checks to top document matching. --- src/bg/RequestGuard.js | 9 +++++---- src/bg/main.js | 10 ++++++++-- src/content/staticNS.js | 2 +- src/content/syncFetchPolicy.js | 2 +- src/nscl | 2 +- src/test/Policy_test.js | 7 ++++++- src/test/run.js | 7 ++++--- src/xss/XSS.js | 5 ++--- 8 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/bg/RequestGuard.js b/src/bg/RequestGuard.js index 03ce484..62ea6ca 100644 --- a/src/bg/RequestGuard.js +++ b/src/bg/RequestGuard.js @@ -259,16 +259,17 @@ var RequestGuard = (() => { } let key = [siteKey, origin][ret.option || 0]; if (!key) return; - let {siteMatch, contextMatch, perms} = ns.policy.get(key, documentUrl); + let contextUrl = sender.tab.url || documentUrl; + let {siteMatch, contextMatch, perms} = ns.policy.get(key, contextUrl); let {capabilities} = perms; if (!capabilities.has(policyType)) { let temp = sender.tab.incognito; // we don't want to store in PBM perms = new Permissions(new Set(capabilities), temp); perms.capabilities.add(policyType); /* TODO: handle contextual permissions - if (documentUrl) { - let context = new URL(documentUrl).origin; - let contextualSites = new Sites([context, perms]); + if (contextUrl) { + let context = Sites.optimalKey(contextUrl); + let contextualSites = new Sites([[context, perms]]); perms = new Permissions(new Set(capabilities), false, contextualSites); } */ diff --git a/src/bg/main.js b/src/bg/main.js index d589387..de01665 100644 --- a/src/bg/main.js +++ b/src/bg/main.js @@ -228,9 +228,15 @@ isEnforced(tabId = -1) { return this.policy.enforced && (tabId === -1 || !this.unrestrictedTabs.has(tabId)); }, - + policyContext(contextualData) { + // contextualData (e.g. a request details object) must contain a tab, a tabId or a documentUrl + // (used as a fallback if tab's top URL cannot be retrieved, e.g. in service workers) + let {tab, tabId, documentUrl} = contextualData; + if (!tab) tab = tabId !== -1 && TabCache.get(tabId); + return tab && tab.url || documentUrl; + }, requestCan(request, capability) { - return !this.isEnforced(request.tabId) || this.policy.can(request.url, capability, request.documentURL); + return !this.isEnforced(request.tabId) || this.policy.can(request.url, capability, this.policyContext(request)); }, computeChildPolicy({url, contextUrl}, sender) { diff --git a/src/content/staticNS.js b/src/content/staticNS.js index ca82384..c5211f5 100644 --- a/src/content/staticNS.js +++ b/src/content/staticNS.js @@ -92,7 +92,7 @@ this.syncFetchPolicy(); } else { this.setup( - browser.runtime.sendSyncMessage({id: "fetchPolicy", url, contextUrl: url}) + browser.runtime.sendSyncMessage({id: "fetchPolicy", url}) ); } }, diff --git a/src/content/syncFetchPolicy.js b/src/content/syncFetchPolicy.js index d9c3518..78d9392 100644 --- a/src/content/syncFetchPolicy.js +++ b/src/content/syncFetchPolicy.js @@ -65,7 +65,7 @@ } let syncFetch = callback => { browser.runtime.sendSyncMessage( - {id: "fetchPolicy", url, contextUrl: url}, + {id: "fetchPolicy", url}, callback); }; debug("Initial readyState and body", document.readyState, document.body); diff --git a/src/nscl b/src/nscl index e8efe68..f04ec6a 160000 --- a/src/nscl +++ b/src/nscl @@ -1 +1 @@ -Subproject commit e8efe68bbdaa458fab7a16c665262422ea508119 +Subproject commit f04ec6afe193f59ce540f5de9e0d184bf7d8a231 diff --git a/src/test/Policy_test.js b/src/test/Policy_test.js index ba34b0e..0c9cdd4 100644 --- a/src/test/Policy_test.js +++ b/src/test/Policy_test.js @@ -30,7 +30,9 @@ p1.set("10", p1.TRUSTED); p1.set("192.168", p1.TRUSTED); p1.set("192.168.69", p1.UNTRUSTED); - // secureDomainKey should be "downgraded" by UTRUSTED, issue #126 + p1.set("facebook.net", new Permissions([], false, + new Sites([[Sites.optimalKey("https://facebook.com"), p1.TRUSTED]]))); + // secureDomainKey should be "downgraded" by UNTRUSTED, issue #126 p1.set(Sites.secureDomainKey("evil.com"), p1.UNTRUSTED); let p2 = new Policy(p1.dry()); debug("p1", JSON.stringify(p1.dry())); @@ -55,6 +57,9 @@ () => p1.can("http://192.168.1.2"), () => p1.can("http://some.onion"), () => !p1.can("http://evil.com"), + () => !p1.can("https://facebook.net"), + () => p1.can("https://facebook.net", "script", "https://www.facebook.com"), + () => !p1.can("https://facebook.net", "script", "http://facebook.com"), ]) Test.run(t); Sites.onionSecure = onionSecureCurrent; Test.report(); diff --git a/src/test/run.js b/src/test/run.js index 7ac01cb..81d6fc2 100644 --- a/src/test/run.js +++ b/src/test/run.js @@ -19,10 +19,11 @@ */ (async () => { - await include("/test/Test.js"); + await include("/nscl/test/Test.js"); Test.include([ - "Policy", - "Storage", + "/nscl/test/Policy_test.js", + "/nscl/test/Storage_test.js", + "/nscl/test/TLD_test.js", "XSS", "embargoed/XSS", ]); diff --git a/src/xss/XSS.js b/src/xss/XSS.js index 89e69fd..8e68ac8 100644 --- a/src/xss/XSS.js +++ b/src/xss/XSS.js @@ -74,12 +74,11 @@ var XSS = (() => { async function requestListener(request) { - if (ns.isEnforced(request.tabId)) { - let {policy} = ns; + { let {type} = request; if (type !== "main_frame") { if (type === "sub_frame") type = "frame"; - if (!policy.can(request.url, type, request.originUrl)) { + if (!ns.requestCan(request, type)) { return ALLOW; // it will be blocked by RequestGuard } }