From 704f2da0673dc714f72b9bb82f6bf648795d4335 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Mon, 6 Sep 2021 20:45:50 +0200 Subject: re-enable sanitizing of data: URLs and also sanitize intrinsics on non-HTML pages where CSP doesn't work --- content/main.js | 78 +++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 65 insertions(+), 13 deletions(-) (limited to 'content/main.js') diff --git a/content/main.js b/content/main.js index b2cc9ed..a183913 100644 --- a/content/main.js +++ b/content/main.js @@ -13,7 +13,6 @@ * IMPORT sign_data * IMPORT gen_nonce * IMPORT is_privileged_url - * IMPORT mozilla_suppress_scripts * IMPORT is_chrome * IMPORT is_mozilla * IMPORT start_activity_info_server @@ -132,10 +131,18 @@ function finish_waiting(waiting) function _wait_for_head(doc, detached_html, callback) { const waiting = {doc, detached_html, callback, observers: []}; - if (try_body_started(waiting)) - return; - waiting.observers = [make_body_start_observer(detached_html, waiting)]; + /* + * For XML and SVG documents, instead of waiting for `', we wait + * for the entire document to finish loading. + */ + if (doc instanceof HTMLDocument) { + if (try_body_started(waiting)) + return; + + waiting.observers = [make_body_start_observer(detached_html, waiting)]; + } + waiting.loaded_cb = () => finish_waiting(waiting); doc.addEventListener("DOMContentLoaded", waiting.loaded_cb); } @@ -200,32 +207,72 @@ function desanitize_script(script, policy) delete script.hachette_blocked_type; } -function apply_hachette_csp_rules(doc, policy) +function apply_hachette_csp_rules(doc, head, policy) { const meta = doc.createElement("meta"); meta.setAttribute("http-equiv", "Content-Security-Policy"); meta.setAttribute("content", csp_rule(policy.nonce)); - doc.head.append(meta); + head.append(meta); /* CSP is already in effect, we can remove the now. */ meta.remove(); } +function sanitize_urls(element) +{ + for (const attribute of [...element.attributes]) { + if (/^(href|src|data)$/i.test(attribute.localName) && + /^data:([^,;]*ml|unknown-content-type)/i.test(attribute.value)) + block_attribute(element, attribute.localName); + } +} + +function start_data_urls_sanitizing(doc) +{ + doc.querySelectorAll("*[href], *[src], *[data]").forEach(sanitize_urls); + const mutation_handler = m => m.addedNodes.forEach(sanitize_urls); + const mo = new MutationObserver(ms => ms.forEach(mutation_handler)); + mo.observe(doc, {childList: true, subtree: true}); +} + +function apply_intrinsics_sanitizing(root_element) +{ + for (const subelem of root_element.querySelectorAll("*")) { + [...subelem.attributes] + .filter(a => /^on/i.test(a.localName)) + .filter(a => /^javascript:/i.test(a.value)) + .forEach(a => block_attribute(subelem, a.localName)); + } +} + async function sanitize_document(doc, policy) { + /* + * Blocking of scripts that are in the DOM from the beginning. Needed for + * Mozilla, harmless on Chromium. + * Note that at least in SVG documents the `src' attr on `