Selective handling of Tor Browser options and work-around for https://bugzilla.mozilla.org/show_bug.cgi?id=1532530

This commit is contained in:
hackademix 2019-03-14 01:57:58 +01:00
parent 3f2453053b
commit d1dd278a81
10 changed files with 138 additions and 22 deletions

View File

@ -267,6 +267,18 @@
"OptFilterXPost": {
"message": "Turn cross-site POST requests into data-less GET requests"
},
"OptScanXUpload": {
"message": "Scan uploads for potential cross-site attacks"
},
"OptBlockUnscannedXPost": {
"message": "Ask confirmation for cross-site POST requests which could not be scanned"
},
"UnscannedXPost": {
"message": "This cross-site request could not be scanned for XSS.\nIt might be innocuous, but NoScript cannot tell for sure. Allow only if you trust both sites."
},
"OptOverrideTorBrowserPolicy": {
"message": "Override Tor Browser's Security Level preset"
},
"Options": {
"message": "Options…"
},

View File

@ -12,7 +12,10 @@ var Defaults = {
sync: {
"global": false,
"xss": true,
"clearclick": true
"xssScanRequestBody": true,
"xssBlockUnscannedPOST": false,
"overrideTorBrowserPolicy": false, // note: Settings.update() on reset will flip this to true
"clearclick": true,
}
};
let defaultsClone = JSON.parse(JSON.stringify(defaults));

View File

@ -379,7 +379,7 @@ var RequestGuard = (() => {
if (pending) {
pending.scriptBlocked = scriptBlocked;
if (!(pending.headersProcessed &&
(scriptBlocked || !ns.isEnforced(tabId) || ns.policy.can(url, "script", request.documentURL))
(scriptBlocked || !ns.requestCan(request, "script"))
)) {
debug("[WARNING] onHeadersReceived %s %o", frameId, tabId,
pending.headersProcessed ? "has been overridden on": "could not process",

View File

@ -81,8 +81,56 @@ var Settings = {
tabId,
unrestrictedTab,
reloadAffected,
isTorBrowser,
} = settings;
if (xssUserChoices) await XSS.saveUserChoices(xssUserChoices);
let oldDebug = ns.local.debug;
let reloadOptionsUI = false;
if (isTorBrowser) {
// Tor Browser-specific settings
ns.defaults.local.isTorBrowser = true; // prevents reset from forgetting
if (!this.gotTorBrowserInit) {
// First initialization message from the Tor Browser
this.gotTorBrowserInit = true;
if (ns.sync.overrideTorBrowserPolicy) {
// If the user chose to override Tor Browser's policy we skip
// copying the Security Level preset on startup (only).
// Manually changing the security level works as usual.
ns.local.isTorBrowser = true;
await ns.save(ns.local);
return;
}
} else {
reloadOptionsUI = true;
}
if (!settings.local) settings.local = {};
settings.local.isTorBrowser = true;
if (!settings.sync) settings.sync = {};
settings.sync.xssScanRequestBody = false;
settings.sync.xssBlockUnscannedPOST = true;
}
if (settings.sync === null) {
// overriden defaults when user manually resets options
// we want the reset options to stick (otherwise it gets very confusing)
ns.defaults.sync.overrideTorBrowserPolicy = true;
reloadOptionsUI = true;
}
await Promise.all(["local", "sync"].map(
async storage => (settings[storage] || // changed or...
settings[storage] === null // ... needs reset to default
) && await ns.save(settings[storage]
? Object.assign(ns[storage], settings[storage]) : ns[storage] = ns.defaults[storage])
));
if (ns.local.debug !== oldDebug) {
await include("/lib/log.js");
if (oldDebug) debug = () => {};
}
if (policy) {
ns.policy = new Policy(policy);
await ns.savePolicy();
@ -95,22 +143,15 @@ var Settings = {
browser.tabs.reload(tabId);
}
let oldDebug = ns.local.debug;
await Promise.all(["local", "sync"].map(
storage => (settings[storage] || // changed or...
settings[storage] === null // ... needs reset to default
) && ns.save(
ns[storage] = settings[storage] || ns.defaults[storage])
));
if (ns.local.debug !== oldDebug) {
await include("/lib/log.js");
if (oldDebug) debug = () => {};
}
if (xssUserChoices) await XSS.saveUserChoices(xssUserChoices);
if (ns.sync.xss) {
XSS.start();
} else {
XSS.stop();
}
if (reloadOptionsUI) await this.reloadOptionsUI();
},
export() {
@ -125,5 +166,15 @@ var Settings = {
async enforceTabRestrictions(tabId, unrestricted = ns.unrestrictedTabs.has(tabId)) {
await ChildPolicies.storeTabInfo(tabId, unrestricted && {unrestricted: true});
return unrestricted;
},
async reloadOptionsUI() {
try {
for (let t of await browser.tabs.query({url: browser.runtime.getManifest().options_ui.page })) {
browser.tabs.reload(t.id);
};
} catch (e) {
error(e);
}
}
}

View File

@ -180,6 +180,10 @@
return this.policy.enforced && (tabId === -1 || !this.unrestrictedTabs.has(tabId));
},
requestCan(request, capability) {
return !this.isEnforced(request.tabId) || this.policy.can(request.url, "script", request.documentURL);
},
start() {
if (this.running) return;
this.running = true;

View File

@ -136,9 +136,19 @@ input[type="file"] {
.opt-group {
padding: 0.5em 0;
}
#xssFaq {
padding: 0.5em 1em;
}
#tb-options {
display: none;
}
.tor #tb-options {
display: initial;
}
#clearclick-options {
display: none;
}

View File

@ -99,17 +99,33 @@
<h3 class="flextabs__tab"><button class="flextabs__toggle">__MSG_SectionAdvanced__</button></h3>
<div class="flextabs__content">
<div class="opt-group">
<span id="xss-opts">
<div id="xss-options" class="opt-group">
<span id="xss-opt">
<input type="checkbox" id="opt-xss"><label for="opt-xss" id="lbl-xss">__MSG_OptFilterXGet__</label>
<span id="xssFaq">(<a href="https://noscript.net/faq#xss" title="https://noscript.net/faq#xss">__MSG_XssFaq__</a>)</span>
<span id="xssFaq">(<a href="https://noscript.net/faq#xss" title="https://noscript.net/faq#xss">__MSG_XssFaq__</a>)</span>
</span>
<button id="btn-delete-xss-choices" disabled>__MSG_XSS_clearUserChoices__</button>
<br />
<span id="xssScanRequestBody-opt">
<input type="checkbox" id="opt-xssScanRequestBody">
<label for="opt-xssScanRequestBody" id="lbl-opt-xssScanRequestBody">__MSG_OptScanXUpload__</label>
</span>
<span id="xssBlockUnscannedPOST-opt">
<input type="checkbox" id="opt-xssBlockUnscannedPOST">
<label for="opt-xssBlockUnscannedPOST" id="lbl-opt-xssBlockUnscannedPOST">__MSG_OptBlockUnscannedXPost__</label>
</span>
</div>
<div id="clearclick-options" class="opt-group">
<input type="checkbox" id="opt-clearclick"><label for="opt-clearclick" id="lbl-clearclick">ClearClick</label>
</div>
<div id="tb-options" class="opt-group">
<span id="overrideTorBrowserPolicy-opt">
<input type="checkbox" id="opt-overrideTorBrowserPolicy">
<label for="opt-overrideTorBrowserPolicy" id="lbl-opt-overrideTorBrowserPolicy">__MSG_OptOverrideTorBrowserPolicy__</label>
</span>
</div>
<section id="debug" class="browser-style">
<div class="opt-group">
<span><input type="checkbox" id="opt-debug"><label id="label-debug" for="opt-debug">Debug</label></span>

View File

@ -8,9 +8,9 @@
let version = browser.runtime.getManifest().version;
document.querySelector("#version").textContent = _("Version", version);
// simple general options
let opt = UI.wireOption;
opt("global", o => {
if (o) {
policy.enforced = !o.checked;
@ -33,6 +33,11 @@
});
opt("xss");
opt("xssScanRequestBody");
opt("xssBlockUnscannedPOST");
opt("overrideTorBrowserPolicy");
{
let button = document.querySelector("#btn-reset");
button.onclick = async () => {

View File

@ -41,6 +41,9 @@ var UI = (() => {
if (UI.local && !UI.local.debug) {
debug = () => {}; // be quiet!
}
if (UI.local) {
document.documentElement.classList.toggle("tor", !!UI.local.isTorBrowser);
}
resolve();
if (UI.onSettings) UI.onSettings();
await HighContrast.init();

View File

@ -114,6 +114,13 @@ var XSS = (() => {
return {
async start() {
let {onBeforeRequest} = browser.webRequest;
let {xssScanRequestBody} = ns.sync;
if (xssScanRequestBody !== this.xssScanRequestBody) {
this.stop();
this.xssScanRequestBody = xssScanRequestBody;
}
this.xssBlockUnscannedPOST = ns.sync.xssBlockUnscannedPOST;
if (onBeforeRequest.hasListener(requestListener)) return;
await include("/legacy/Legacy.js");
@ -135,7 +142,9 @@ var XSS = (() => {
onBeforeRequest.addListener(requestListener, {
urls: ["*://*/*"],
types: ["main_frame", "sub_frame", "object"]
}, ["blocking", "requestBody"]);
},
// work-around for https://bugzilla.mozilla.org/show_bug.cgi?id=1532530
xssScanRequestBody ? ["blocking", "requestBody"] : ["blocking"]);
},
stop() {
@ -233,8 +242,11 @@ var XSS = (() => {
ic.reset();
let postInjection = xssReq.isPost &&
request.requestBody && request.requestBody.formData &&
ic.checkPost(request.requestBody.formData, skipParams);
(XSS.xssScanRequestBody ?
request.requestBody && request.requestBody.formData &&
ic.checkPost(request.requestBody.formData, skipParams)
: XSS.xssBlockUnscannedPOST && ns.requestCan(request, "script") && _("UnscannedXPost")
);
let protectName = ic.nameAssignment;
let urlInjection = ic.checkUrl(destUrl, skipRx);