Project

General

Profile

« Previous | Next » 

Revision 8b823e1a

Added by jahoti about 2 years ago

Revamp signatures and break header caching on FF

Signatures, instead of consisting of the secure salt followed by the unique
value generated from the URL, are now the unique value generated from the
policy value (which will follow them) succeeded by the URL.

CSP headers are now always cleared on FF, regardless of whether the page
is whitelisted or not. This means whitelisting takes effect on page reload,
rather than only when caching occurs. However, it obviously presents security
issues; refinment will occur in a future commit.

View differences:

background/policy_injector.js
12 12
 * IMPORT get_storage
13 13
 * IMPORT browser
14 14
 * IMPORT is_chrome
15
 * IMPORT is_mozilla
15 16
 * IMPORT gen_unique
16 17
 * IMPORT gen_nonce
17 18
 * IMPORT url_item
......
45 46
function url_inject(details)
46 47
{
47 48
    const targets = url_extract_policy(details.url);
48
    if (targets.policy) {
49
    if (targets.valid_sig) {
49 50
	return;
50
    } else if (targets.signed) {
51
    } else if (targets.policy) {
51 52
	/* Redirect; update policy */
52 53
	targets.target = targets.target2;
53 54
	delete targets.target2
54 55
    }
55 56

  
56
    let redirect_url = targets.base_url + targets.sig;
57 57
    let [pattern, settings] = query_best(targets.base_url);
58 58
    if (!pattern)
59 59
	/* Defaults */
60 60
	settings = {};
61 61
    
62 62
    const policy = {allow: settings.allow, nonce: gen_nonce()};
63
    const policy_string = encodeURIComponent(JSON.stringify(policy));
64
    const sig = gen_unique(policy_string + targets.base_url);
63 65
    
64
    redirect_url += encodeURIComponent(JSON.stringify(policy));
66
    let redirect_url = targets.base_url + '#' + sig + policy_string;
65 67
    if (targets.target)
66 68
	redirect_url += targets.target;
67 69
    if (targets.target2)
......
73 75
function inject(details)
74 76
{
75 77
    const targets = url_extract_policy(details.url);
76
    if (!targets.policy)
78
    if (!targets.valid_sig)
77 79
	/* Block unsigned requests */
78 80
	return {cancel: true};
79 81

  
80 82
    const rule = csp_rule(targets.policy.nonce);
81 83

  
82
    var headers;
84
    var headers = details.responseHeaders;
83 85

  
84
    if (targets.policy.allow) {
86
    if (!targets.policy.allow || is_mozilla)
85 87
	/*
86
	 * Chrome doesn't have the buggy behavior of repeatedly injecting a
87
	 * header we injected once. Firefox does and we have to remove it there.
88
	 * Chrome doesn't have the buggy behavior of caching headers
89
	 * we injected. Firefox does and we have to remove it there.
88 90
	 */
89
	if (is_chrome)
90
	    return {cancel: false};
91

  
92
	headers = details.responseHeaders.filter(h => !is_our_header(h, rule));
93
    } else {
94
	headers = details.responseHeaders.filter(h => !is_csp_header(h));
91
	headers = headers.filter(h => !is_csp_header(h));
95 92

  
93
    if (!targets.policy.allow)
96 94
	headers.push({
97 95
	    name : header_name,
98 96
	    value : rule
99 97
	});
100
    }
101 98

  
102 99
    return {responseHeaders: headers};
103 100
}
common/misc.js
35 35
function get_secure_salt()
36 36
{
37 37
    if (is_chrome)
38
	return browser.runtime.getManifest().key.substring(0, 36);
38
	return browser.runtime.getManifest().key.substring(0, 50);
39 39
    else
40
	return browser.runtime.getURL("dummy").substr(16, 36);
40
	return browser.runtime.getURL("dummy");
41 41
}
42 42

  
43 43
/*
......
107 107
/* Extract any policy present in the URL */
108 108
function url_extract_policy(url)
109 109
{
110
    var policy_string;
110 111
    const targets = url_extract_target(url);
111
    const key = '#' + get_secure_salt();
112
    targets.sig = key + gen_unique(targets.base_url);
113 112
    
114
    if (targets.target && targets.target.startsWith(key)) {
115
	targets.signed = true;
116
	if (targets.target.startsWith(targets.sig))
117
	    try {
118
		const policy_string = targets.target.substring(101);
119
		targets.policy = JSON.parse(decodeURIComponent(policy_string));
120
	    } catch (e) {
121
		/* TODO what should happen here? */
122
	    }
113
    try {
114
	policy_string = targets.target.substring(65);
115
	targets.policy = JSON.parse(decodeURIComponent(policy_string));
116
    } catch (e) {
117
	/* TODO what should happen here? */
118
    }
119
    
120
    if (targets.policy) {
121
	const sig = gen_unique(policy_string + targets.base_url);
122
	targets.valid_sig = targets.target.substring(1, 65) === sig;
123 123
    }
124 124

  
125 125
    return targets;
content/main.js
100 100

  
101 101
if (!is_privileged_url(document.URL)) {
102 102
    const targets = url_extract_policy(document.URL);
103
    targets.policy = targets.policy || {};
104
    const nonce = targets.policy.nonce || gen_nonce();
105

  
106
    if (targets.signed)
103
    if (targets.policy) {
107 104
	if (targets.target2 !== undefined)
108 105
	    window.location.href = targets.base_url + targets.target2;
109 106
	else
110 107
	    history.replaceState(null, "", targets.base_url);
111

  
108
    }
109
    
110
    targets.policy = targets.valid_sig ? targets.policy : {};
111
    
112
    const nonce = targets.policy.nonce || gen_nonce();
112 113
    start_activity_info_server();
113 114
    handle_page_actions(nonce);
114 115

  

Also available in: Unified diff