From 014f2a2f4e2071c35314d67285711f0f4615266b Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Wed, 18 Aug 2021 17:53:57 +0200 Subject: implement smuggling via cookies instead of URL --- common/misc.js | 84 ++++++++++++---------------------------------------------- 1 file changed, 17 insertions(+), 67 deletions(-) (limited to 'common/misc.js') diff --git a/common/misc.js b/common/misc.js index 3c7dc46..39c696f 100644 --- a/common/misc.js +++ b/common/misc.js @@ -45,11 +45,6 @@ function gen_nonce(length) // Default 16 return Uint8toHex(randomData); } -function gen_unique(url) -{ - return sha256(get_secure_salt() + url); -} - function get_secure_salt() { if (is_chrome) @@ -58,72 +53,29 @@ function get_secure_salt() return browser.runtime.getURL("dummy"); } -/* - * stripping url from query and target (everything after `#' or `?' - * gets removed) - */ -function url_item(url) -{ - let url_re = /^([^?#]*).*$/; - let match = url_re.exec(url); - return match[1]; -} - -/* - * Assume a url like: - * https://example.com/green?illuminati=confirmed##winky - * This function will make it into an object like: - * { - * "base_url": "https://example.com/green?illuminati=confirmed", - * "target": "#", - * "target2": "#winky", - * "policy": , - * "current": - * } - * In case url doesn't have 2 #'s, target2 and target can be set to undefined. - */ -function url_extract_target(url) +function extract_signed(signature, data, times) { - const url_re = /^([^#]*)((#[^#]*)(#.*)?)?$/; - const match = url_re.exec(url); - const targets = { - base_url: match[1], - target: match[3] || "", - target2: match[4] || "" - }; - if (!targets.target) - return targets; - - /* %7B -> { */ - const index = targets.target.indexOf('%7B'); - if (index === -1) - return targets; - const now = new Date(); - const sig = targets.target.substring(1, index); - const policy = targets.target.substring(index); - if (sig !== sign_policy(policy, now) && - sig !== sign_policy(policy, now, -1)) - return targets; + times ||= [[now], [now, -1]]; + + const reductor = + (ok, time) => ok || signature === sign_data(data, ...time); + if (!times.reduce(reductor, false)) + return undefined; try { - targets.policy = JSON.parse(decodeURIComponent(policy)); - targets.current = targets.policy.base_url === targets.base_url; + return JSON.parse(decodeURIComponent(data)); } catch (e) { /* This should not be reached - it's our self-produced valid JSON. */ console.log("Unexpected internal error - invalid JSON smuggled!", e); } - - return targets; } /* csp rule that blocks all scripts except for those injected by us */ function csp_rule(nonce) { - let rule = `script-src 'nonce-${nonce}';`; - if (is_chrome) - rule += `script-src-elem 'nonce-${nonce}';`; - return rule; + const rule = `'nonce-${nonce}'`; + return `script-src ${rule}; script-src-elem ${rule}; script-src-attr 'none'; prefetch-src 'none';`; } /* @@ -149,10 +101,10 @@ function is_privileged_url(url) return !!/^(chrome(-extension)?|moz-extension):\/\/|^about:/i.exec(url); } -/* Sign a given policy for a given time */ -function sign_policy(policy, now, hours_offset) { +/* Sign a given string for a given time */ +function sign_data(data, now, hours_offset) { let time = Math.floor(now / 3600000) + (hours_offset || 0); - return gen_unique(time + policy); + return sha256(get_secure_salt() + time + data); } /* Parse a CSP header */ @@ -175,11 +127,11 @@ function parse_csp(csp) { } /* Make CSP headers do our bidding, not interfere */ -function sanitize_csp_header(header, rule, block) +function sanitize_csp_header(header, rule, allow) { const csp = parse_csp(header.value); - if (block) { + if (!allow) { /* No snitching */ delete csp['report-to']; delete csp['report-uri']; @@ -223,10 +175,8 @@ const matchers = { /* * EXPORTS_START * EXPORT gen_nonce - * EXPORT gen_unique - * EXPORT url_item - * EXPORT url_extract_target - * EXPORT sign_policy + * EXPORT extract_signed + * EXPORT sign_data * EXPORT csp_rule * EXPORT nice_name * EXPORT open_in_settings -- cgit v1.2.3