aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjahoti <jahoti@tilde.team>2021-07-12 00:00:00 +0000
committerjahoti <jahoti@tilde.team>2021-07-12 00:00:00 +0000
commitdcfc78b0d175bee7b3b7e273282078d50bd4ca09 (patch)
treec5cc3a032ec1cdcc548bfdc8f0209c43bd14114d
parent0e002513d443ef7cddcc17acf178478844f609e9 (diff)
downloadbrowser-extension-dcfc78b0d175bee7b3b7e273282078d50bd4ca09.tar.gz
browser-extension-dcfc78b0d175bee7b3b7e273282078d50bd4ca09.zip
Stop using the nonce consistently for a URL
Nonces are now randomly generated, either in the page (for non-HTTP(S) pages) or by a background module which stores them by tab and frame IDs. In order to support the increased variance in nonce-generating methods and allow them to be loaded from the background, handle_page_actions is now invoked separately according to (non-)blocking mechanism.
-rw-r--r--background/nonce_store.js30
-rw-r--r--background/page_actions_server.js2
-rw-r--r--background/policy_injector.js4
-rw-r--r--common/misc.js19
-rw-r--r--content/main.js21
-rw-r--r--content/page_actions.js4
-rw-r--r--copyright6
7 files changed, 76 insertions, 10 deletions
diff --git a/background/nonce_store.js b/background/nonce_store.js
new file mode 100644
index 0000000..9370876
--- /dev/null
+++ b/background/nonce_store.js
@@ -0,0 +1,30 @@
+/**
+ * Central management of HTTP(S) nonces
+ *
+ * Copyright (C) 2021 jahoti
+ * Redistribution terms are gathered in the `copyright' file.
+ */
+
+/*
+ * IMPORTS_START
+ * IMPORT gen_nonce
+ * IMPORTS_END
+ */
+
+var nonces = {};
+
+function retrieve_nonce(tabId, frameId, update)
+{
+ let code = tabId + '.' + frameId;
+ console.log('Nonce for ' + code + ' ' + (update ? 'created/updated' : 'requested'));
+ if (update)
+ nonces[code] = gen_nonce();
+
+ return nonces[code];
+}
+
+/*
+ * EXPORTS_START
+ * EXPORT retrieve_nonce
+ * EXPORTS_END
+ */
diff --git a/background/page_actions_server.js b/background/page_actions_server.js
index 2d9c333..d92b870 100644
--- a/background/page_actions_server.js
+++ b/background/page_actions_server.js
@@ -11,6 +11,7 @@
* IMPORT TYPE_PREFIX
* IMPORT CONNECTION_TYPE
* IMPORT browser
+ * IMPORT retrieve_nonce
* IMPORT listen_for_connection
* IMPORT sha256
* IMPORT get_query_best
@@ -137,6 +138,7 @@ function handle_message(port, message, handler)
function new_connection(port)
{
console.log("new page actions connection!");
+ port.postMessage(['nonce', retrieve_nonce((port.sender.tab || '').id, port.sender.frameId)]);
let handler = [];
handler.push(m => handle_message(port, m, handler));
port.onMessage.addListener(handler[0]);
diff --git a/background/policy_injector.js b/background/policy_injector.js
index eb67963..9f79425 100644
--- a/background/policy_injector.js
+++ b/background/policy_injector.js
@@ -11,7 +11,7 @@
* IMPORT get_storage
* IMPORT browser
* IMPORT is_chrome
- * IMPORT gen_unique
+ * IMPORT retrieve_nonce
* IMPORT url_item
* IMPORT get_query_best
* IMPORT csp_rule
@@ -45,7 +45,7 @@ function inject(details)
const [pattern, settings] = query_best(url);
- const nonce = gen_unique(url);
+ const nonce = retrieve_nonce(details.tabId, details.frameId, true);
const rule = csp_rule(nonce);
var headers;
diff --git a/common/misc.js b/common/misc.js
index 8b56e79..7e48059 100644
--- a/common/misc.js
+++ b/common/misc.js
@@ -2,6 +2,7 @@
* Myext miscellaneous operations refactored to a separate file
*
* Copyright (C) 2021 Wojtek Kosior
+ * Copyright (C) 2021 jahoti
* Redistribution terms are gathered in the `copyright' file.
*/
@@ -18,6 +19,23 @@
* generating unique, per-site value that can be computed synchronously
* and is impossible to guess for a malicious website
*/
+
+/* Uint8toHex is a separate function not exported as (a) it's useful and (b) it will be used in crypto.subtle-based digests */
+function Uint8toHex(data)
+{
+ let returnValue = '';
+ for (let byte of data)
+ returnValue += ('00' + byte.toString(16)).slice(-2);
+ return returnValue;
+}
+
+function gen_nonce(length) // Default 16
+{
+ let randomData = new Uint8Array(length || 16);
+ crypto.getRandomValues(randomData);
+ return Uint8toHex(randomData);
+}
+
function gen_unique(url)
{
return sha256(get_secure_salt() + url);
@@ -98,6 +116,7 @@ function is_privileged_url(url)
/*
* EXPORTS_START
* EXPORT gen_unique
+ * EXPORT gen_nonce
* EXPORT url_item
* EXPORT url_extract_target
* EXPORT csp_rule
diff --git a/content/main.js b/content/main.js
index 9acf749..3204a8a 100644
--- a/content/main.js
+++ b/content/main.js
@@ -2,15 +2,18 @@
* Myext main content script run in all frames
*
* Copyright (C) 2021 Wojtek Kosior
+ * Copyright (C) 2021 jahoti
* Redistribution terms are gathered in the `copyright' file.
*/
/*
* IMPORTS_START
+ * IMPORT CONNECTION_TYPE
* IMPORT handle_page_actions
* IMPORT url_item
* IMPORT url_extract_target
* IMPORT gen_unique
+ * IMPORT gen_nonce
* IMPORT csp_rule
* IMPORT is_privileged_url
* IMPORT sanitize_attributes
@@ -113,7 +116,7 @@ function inject_csp(head)
let meta = document.createElement("meta");
meta.setAttribute("http-equiv", "Content-Security-Policy");
- meta.setAttribute("content", csp_rule(unique));
+ meta.setAttribute("content", csp_rule(nonce));
if (head.firstElementChild === null)
head.appendChild(meta);
@@ -123,13 +126,23 @@ function inject_csp(head)
if (!is_privileged_url(document.URL)) {
start_activity_info_server();
- handle_page_actions(unique);
+ var nonce, port = browser.runtime.connect({name : CONNECTION_TYPE.PAGE_ACTIONS});
if (is_http()) {
- /* rely on CSP injected through webRequest */
+ /* rely on CSP injected through webRequest, at the cost of having to fetch a nonce via messaging */
+ const nonce_capturer = msg => {
+ port.onMessage.removeListener(nonce_capturer);
+ handle_page_actions(msg[1], port);
+ };
+
+ port.onMessage.addListener(nonce_capturer);
+
} else if (is_whitelisted()) {
- /* do not block scripts at all */
+ /* do not block scripts at all; as a result, there is no need for a green-lighted nonce */
+ handle_page_actions(null, port);
} else {
+ nonce = gen_nonce();
+ handle_page_actions(nonce, port);
block_nodes_recursively(document.documentElement);
if (is_chrome) {
diff --git a/content/page_actions.js b/content/page_actions.js
index fd405fe..dff5f71 100644
--- a/content/page_actions.js
+++ b/content/page_actions.js
@@ -7,7 +7,6 @@
/*
* IMPORTS_START
- * IMPORT CONNECTION_TYPE
* IMPORT browser
* IMPORT report_script
* IMPORT report_settings
@@ -55,9 +54,8 @@ function add_script(script_text)
report_script(script_text);
}
-function handle_page_actions(script_nonce) {
+function handle_page_actions(script_nonce, port) { // Add port as an argument so we can "pre-receive" a nonce in main.js
document.addEventListener("DOMContentLoaded", document_loaded);
- port = browser.runtime.connect({name : CONNECTION_TYPE.PAGE_ACTIONS});
port.onMessage.addListener(handle_message);
port.postMessage({url: document.URL});
diff --git a/copyright b/copyright
index a01c1fe..93e241b 100644
--- a/copyright
+++ b/copyright
@@ -10,7 +10,7 @@ Files: build.sh
Copyright: 2021 Wojtek Kosior <koszko@koszko.org>
License: CC0
-Files: manifest.json
+Files: manifest.json common/misc.js content/main.js
Copyright: 2021 Wojtek Kosior <koszko@koszko.org>
2021 jahoti <jahoti@tilde.team>
License: GPL-3+-javascript or Alicense-1.0
@@ -46,6 +46,10 @@ License: Expat
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+Files: background/nonce_store.js
+Copyright: 2021 jahoti <jahoti@tilde.team>
+License: GPL-3+-javascript or Alicense-1.0
+
Files: content/freezer.js
Copyright: 2005-2021 Giorgio Maone - https://maone.net
2021 jahoti <jahoti@tilde.team>