aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWojtek Kosior <wk@koszkonutek-tmp.pl.eu.org>2021-05-13 12:32:22 +0200
committerWojtek Kosior <wk@koszkonutek-tmp.pl.eu.org>2021-05-13 12:32:22 +0200
commitc4ed1b8d44c37938aaa9b12674077274554742eb (patch)
treef51381ab7bf3bd0ec9fd9f1002081760bdd56d4a
parent57f32a269a06ec5102b08824d251afa5456d4195 (diff)
downloadbrowser-extension-c4ed1b8d44c37938aaa9b12674077274554742eb.tar.gz
browser-extension-c4ed1b8d44c37938aaa9b12674077274554742eb.zip
utilize CSP for blocking
-rw-r--r--TODOS.org10
-rw-r--r--content/main.js32
-rw-r--r--content/page_actions.js6
3 files changed, 37 insertions, 11 deletions
diff --git a/TODOS.org b/TODOS.org
index c06616a..b2b1edf 100644
--- a/TODOS.org
+++ b/TODOS.org
@@ -23,18 +23,15 @@ TODO:
- find some way not to require each chrome user to modify manifest.json
- rename the extension to something good
- port to gecko-based browsers -- CRUCIAL
-- make it possible to modify CSP to suit our custom scripts' needs
- - find a way to additionally block all other scripts using CSP
- as an additional safety measure
+- make sure page's own csp doesn't block our scripts
- make blocking more torough -- CRUCIAL
- - also block intrinsics -- CRUCIAL
- mind the data: urls -- CRUCIAL
-- find out how and make it possible to whitelist non-https urls
+- find out how and make it possible to whitelist non-https urls and
+ whether we can inject csp to them
- create a repository to host scripts
- enable the extension to automatically fetch script substitutes from the repo
- make it possible to inject scripts to arbitrary places in DOM
- make script blocking code omit those scripts
-- facilitate waiting for script injection until DOM has loaded
- check if prerendering has to be blocked -- CRUCIAL
- block prefetch
- rearrange files in extension, add some mechanism to build the extension
@@ -43,6 +40,7 @@ TODO:
- perform never-ending refactoring of already-written code
DONE:
+- find a way to additionally block all other scripts using CSP -- DONE 2021-05-13
- only allow a single injection payload for page -- DONE 2021-05-13
- rename "bundles" to "bags" to avoid confusion with Web Bundles -- DONE 2021-05-12
- use non-predictable value in place of "myext-allow", utilizing hashes -- DONE 2021-05-12
diff --git a/content/main.js b/content/main.js
index c7f57bb..507a740 100644
--- a/content/main.js
+++ b/content/main.js
@@ -25,6 +25,8 @@
let url = url_item(document.URL);
let unique = gen_unique(url);
+ let nonce = unique.substring(1);
+
var block = true;
if (first_target !== undefined &&
first_target === unique) {
@@ -47,10 +49,20 @@
}
for (let mutation of mutations) {
for (let node of mutation.addedNodes) {
- if (node.tagName === "SCRIPT")
+ /*
+ * Modifying <script> element doesn't always prevent its
+ * execution in some Mozilla browsers. Additional blocking
+ * through CSP meta tag injection is required.
+ */
+ if (node.tagName === "SCRIPT") {
block_script(node);
- else
- sanitize_attributes(node);
+ continue;
+ }
+
+ sanitize_attributes(node);
+
+ if (node.tagName === "HEAD")
+ inject_csp(node);
}
}
}
@@ -68,6 +80,18 @@
node.setAttribute("type", "application/json");
}
+ function inject_csp(node)
+ {
+ console.log('injecting CSP');
+ let meta = document.createElement("meta");
+ meta.setAttribute("http-equiv", "Content-Security-Policy");
+ meta.setAttribute("content", `\
+script-src 'nonce-${nonce}'; \
+script-src-elem 'nonce-${nonce}';\
+`);
+ node.appendChild(meta);
+ }
+
function sanitize_attributes(node)
{
if (node.attributes === undefined)
@@ -99,5 +123,5 @@
});
}
- handle_page_actions();
+ handle_page_actions(nonce);
})();
diff --git a/content/page_actions.js b/content/page_actions.js
index 047bf24..eee0599 100644
--- a/content/page_actions.js
+++ b/content/page_actions.js
@@ -17,6 +17,7 @@
var port;
var loaded = false;
var scripts_awaiting = [];
+ var nonce;
function handle_message(message)
{
@@ -49,14 +50,17 @@
{
let script = document.createElement("script");
script.textContent = script_text;
+ script.setAttribute("nonce", nonce);
document.body.appendChild(script);
}
- function handle_page_actions() {
+ function handle_page_actions(script_nonce) {
document.addEventListener("DOMContentLoaded", document_loaded);
port = browser.runtime.connect({name : CONNECTION_TYPE.PAGE_ACTIONS});
port.onMessage.addListener(handle_message);
port.postMessage({url: document.URL});
+
+ nonce = script_nonce;
}
window.handle_page_actions = handle_page_actions;