diff options
author | hackademix | 2019-05-27 00:28:01 +0200 |
---|---|---|
committer | hackademix | 2019-05-27 00:28:01 +0200 |
commit | 5597c4b0e53b27ea479383f4a890837417e6cc15 (patch) | |
tree | 73a27f048003e226e818cbcbfcde1aa8a83d0039 /src/xss/XSS.js | |
parent | 4826128e43435a5053bd41b8251fb08319160f6f (diff) | |
download | noscript-5597c4b0e53b27ea479383f4a890837417e6cc15.tar.gz noscript-5597c4b0e53b27ea479383f4a890837417e6cc15.tar.xz noscript-5597c4b0e53b27ea479383f4a890837417e6cc15.zip |
XSS Filter made further asynchronous, prevents freezes on complex JSON payloads.
Diffstat (limited to 'src/xss/XSS.js')
-rw-r--r-- | src/xss/XSS.js | 43 |
1 files changed, 33 insertions, 10 deletions
diff --git a/src/xss/XSS.js b/src/xss/XSS.js index 93230cd..51216d8 100644 --- a/src/xss/XSS.js +++ b/src/xss/XSS.js @@ -5,6 +5,7 @@ var XSS = (() => { const ABORT = {cancel: true}, ALLOW = {}; let promptsMap = new Map(); + let timingsMap = new Map(); async function getUserResponse(xssReq) { let {originKey} = xssReq; @@ -21,6 +22,14 @@ var XSS = (() => { return null; } + function doneListener(request) { + let timing = timingsMap.get(request.id); + if (timing) { + timing.interrupted = true; + timingsMap.delete(request.id); + } + } + async function requestListener(request) { if (ns.isEnforced(request.tabId)) { @@ -40,19 +49,24 @@ var XSS = (() => { let data; let reasons; + try { + reasons = await XSS.maybe(xssReq); if (!reasons) return ALLOW; data = []; } catch (e) { error(e, "XSS filter processing %o", xssReq); + if (e instanceof TimingException) { + // we don't want prompts if the request expired / errored first + return; + } reasons = { urlInjection: true }; data = [e.toString()]; } - let prompting = (async () => { userResponse = await getUserResponse(xssReq); if (userResponse) return userResponse; @@ -115,7 +129,7 @@ var XSS = (() => { async start() { if (!UA.isMozilla) return; // async webRequest is supported on Mozilla only - let {onBeforeRequest} = browser.webRequest; + let {onBeforeRequest, onCompleted, onErrorOccurred} = browser.webRequest; if (onBeforeRequest.hasListener(requestListener)) return; @@ -134,11 +148,15 @@ var XSS = (() => { } XSS.Exceptions.setWhitelist(null); } - - onBeforeRequest.addListener(requestListener, { + let filter = { urls: ["*://*/*"], types: ["main_frame", "sub_frame", "object"] - }, ["blocking", "requestBody"]); + }; + onBeforeRequest.addListener(requestListener, filter, ["blocking", "requestBody"]); + if (!onCompleted.hasListener(doneListener)) { + onCompleted.addListener(doneListener, filter); + onErrorOccurred.addListener(doneListener, filter); + } }, stop() { @@ -235,17 +253,22 @@ var XSS = (() => { let {destUrl} = xssReq; await include("/xss/InjectionChecker.js"); - let ic = await this.InjectionChecker; - ic.reset(); + let ic = new (await this.InjectionChecker)(); + let {timing} = ic; + timingsMap.set(request.id, timing); let postInjection = xssReq.isPost && request.requestBody && request.requestBody.formData && - ic.checkPost(request.requestBody.formData, skipParams); + await ic.checkPost(request.requestBody.formData, skipParams); + + if (timing.tooLong) { + log("[XSS] Long check (%s ms) - %s", timing.elapsed, JSON.stringify(xssReq)); + } let protectName = ic.nameAssignment; - let urlInjection = ic.checkUrl(destUrl, skipRx); + let urlInjection = await ic.checkUrl(destUrl, skipRx); protectName = protectName || ic.nameAssignment; - ic.reset(); + return !(protectName || postInjection || urlInjection) ? null : { protectName, postInjection, urlInjection }; } |