Project

General

Profile

« Previous | Next » 

Revision dcfc78b0

Added by jahoti about 2 years ago

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.

View differences:

background/nonce_store.js
1
/**
2
 * Central management of HTTP(S) nonces
3
 *
4
 * Copyright (C) 2021 jahoti
5
 * Redistribution terms are gathered in the `copyright' file.
6
 */
7

  
8
/*
9
 * IMPORTS_START
10
 * IMPORT gen_nonce
11
 * IMPORTS_END
12
 */
13

  
14
var nonces = {};
15

  
16
function retrieve_nonce(tabId, frameId, update)
17
{
18
    let code = tabId + '.' + frameId;
19
    console.log('Nonce for ' + code + ' ' + (update ? 'created/updated' : 'requested'));
20
    if (update)
21
        nonces[code] = gen_nonce();
22
    
23
    return nonces[code];
24
}
25

  
26
/*
27
 * EXPORTS_START
28
 * EXPORT retrieve_nonce
29
 * EXPORTS_END
30
 */
background/page_actions_server.js
11 11
 * IMPORT TYPE_PREFIX
12 12
 * IMPORT CONNECTION_TYPE
13 13
 * IMPORT browser
14
 * IMPORT retrieve_nonce
14 15
 * IMPORT listen_for_connection
15 16
 * IMPORT sha256
16 17
 * IMPORT get_query_best
......
137 138
function new_connection(port)
138 139
{
139 140
    console.log("new page actions connection!");
141
    port.postMessage(['nonce', retrieve_nonce((port.sender.tab || '').id, port.sender.frameId)]);
140 142
    let handler = [];
141 143
    handler.push(m => handle_message(port, m, handler));
142 144
    port.onMessage.addListener(handler[0]);
background/policy_injector.js
11 11
 * IMPORT get_storage
12 12
 * IMPORT browser
13 13
 * IMPORT is_chrome
14
 * IMPORT gen_unique
14
 * IMPORT retrieve_nonce
15 15
 * IMPORT url_item
16 16
 * IMPORT get_query_best
17 17
 * IMPORT csp_rule
......
45 45

  
46 46
    const [pattern, settings] = query_best(url);
47 47

  
48
    const nonce = gen_unique(url);
48
    const nonce = retrieve_nonce(details.tabId, details.frameId, true);
49 49
    const rule = csp_rule(nonce);
50 50

  
51 51
    var headers;
common/misc.js
2 2
 * Myext miscellaneous operations refactored to a separate file
3 3
 *
4 4
 * Copyright (C) 2021 Wojtek Kosior
5
 * Copyright (C) 2021 jahoti
5 6
 * Redistribution terms are gathered in the `copyright' file.
6 7
 */
7 8

  
......
18 19
 * generating unique, per-site value that can be computed synchronously
19 20
 * and is impossible to guess for a malicious website
20 21
 */
22

  
23
/* Uint8toHex is a separate function not exported as (a) it's useful and (b) it will be used in crypto.subtle-based digests */
24
function Uint8toHex(data)
25
{
26
    let returnValue = '';
27
    for (let byte of data)
28
	returnValue += ('00' + byte.toString(16)).slice(-2);
29
    return returnValue;
30
}
31

  
32
function gen_nonce(length) // Default 16
33
{
34
    let randomData = new Uint8Array(length || 16);
35
    crypto.getRandomValues(randomData);
36
    return Uint8toHex(randomData);
37
}
38

  
21 39
function gen_unique(url)
22 40
{
23 41
    return sha256(get_secure_salt() + url);
......
98 116
/*
99 117
 * EXPORTS_START
100 118
 * EXPORT gen_unique
119
 * EXPORT gen_nonce
101 120
 * EXPORT url_item
102 121
 * EXPORT url_extract_target
103 122
 * EXPORT csp_rule
content/main.js
2 2
 * Myext main content script run in all frames
3 3
 *
4 4
 * Copyright (C) 2021 Wojtek Kosior
5
 * Copyright (C) 2021 jahoti
5 6
 * Redistribution terms are gathered in the `copyright' file.
6 7
 */
7 8

  
8 9
/*
9 10
 * IMPORTS_START
11
 * IMPORT CONNECTION_TYPE
10 12
 * IMPORT handle_page_actions
11 13
 * IMPORT url_item
12 14
 * IMPORT url_extract_target
13 15
 * IMPORT gen_unique
16
 * IMPORT gen_nonce
14 17
 * IMPORT csp_rule
15 18
 * IMPORT is_privileged_url
16 19
 * IMPORT sanitize_attributes
......
113 116

  
114 117
    let meta = document.createElement("meta");
115 118
    meta.setAttribute("http-equiv", "Content-Security-Policy");
116
    meta.setAttribute("content", csp_rule(unique));
119
    meta.setAttribute("content", csp_rule(nonce));
117 120

  
118 121
    if (head.firstElementChild === null)
119 122
	head.appendChild(meta);
......
123 126

  
124 127
if (!is_privileged_url(document.URL)) {
125 128
    start_activity_info_server();
126
    handle_page_actions(unique);
129
    var nonce, port = browser.runtime.connect({name : CONNECTION_TYPE.PAGE_ACTIONS});
127 130

  
128 131
    if (is_http()) {
129
	/* rely on CSP injected through webRequest */
132
	/* rely on CSP injected through webRequest, at the cost of having to fetch a nonce via messaging */
133
	const nonce_capturer = msg => {
134
	    port.onMessage.removeListener(nonce_capturer);
135
	    handle_page_actions(msg[1], port);
136
	};
137
	
138
	port.onMessage.addListener(nonce_capturer);
139
	
130 140
    } else if (is_whitelisted()) {
131
	/* do not block scripts at all */
141
	/* do not block scripts at all; as a result, there is no need for a green-lighted nonce */
142
	handle_page_actions(null, port);
132 143
    } else {
144
	nonce = gen_nonce();
145
	handle_page_actions(nonce, port);
133 146
	block_nodes_recursively(document.documentElement);
134 147

  
135 148
	if (is_chrome) {
content/page_actions.js
7 7

  
8 8
/*
9 9
 * IMPORTS_START
10
 * IMPORT CONNECTION_TYPE
11 10
 * IMPORT browser
12 11
 * IMPORT report_script
13 12
 * IMPORT report_settings
......
55 54
    report_script(script_text);
56 55
}
57 56

  
58
function handle_page_actions(script_nonce) {
57
function handle_page_actions(script_nonce, port) { // Add port as an argument so we can "pre-receive" a nonce in main.js
59 58
    document.addEventListener("DOMContentLoaded", document_loaded);
60
    port = browser.runtime.connect({name : CONNECTION_TYPE.PAGE_ACTIONS});
61 59
    port.onMessage.addListener(handle_message);
62 60
    port.postMessage({url: document.URL});
63 61

  
copyright
10 10
Copyright: 2021 Wojtek Kosior <koszko@koszko.org>
11 11
License: CC0
12 12

  
13
Files: manifest.json
13
Files: manifest.json common/misc.js content/main.js
14 14
Copyright: 2021 Wojtek Kosior <koszko@koszko.org>
15 15
   2021 jahoti <jahoti@tilde.team>
16 16
License: GPL-3+-javascript or Alicense-1.0
......
46 46
 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
47 47
 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
48 48

  
49
Files: background/nonce_store.js
50
Copyright: 2021 jahoti <jahoti@tilde.team>
51
License: GPL-3+-javascript or Alicense-1.0
52

  
49 53
Files: content/freezer.js
50 54
Copyright: 2005-2021 Giorgio Maone - https://maone.net
51 55
   2021 jahoti <jahoti@tilde.team>

Also available in: Unified diff