From 2cdbbe2d579a9f2b24f747cdf3640ef99d7dccd3 Mon Sep 17 00:00:00 2001 From: hackademix Date: Mon, 27 Dec 2021 20:01:35 +0100 Subject: [PATCH] [XSS] Precomputed invalid identifier chars regular expression. --- src/test/XSS_test.js | 33 +++++++++++++++++++++++++++++++ src/xss/InjectionChecker.js | 39 ++----------------------------------- 2 files changed, 35 insertions(+), 37 deletions(-) diff --git a/src/test/XSS_test.js b/src/test/XSS_test.js index f11d60f..e2da8d7 100644 --- a/src/test/XSS_test.js +++ b/src/test/XSS_test.js @@ -33,4 +33,37 @@ if (UA.isMozilla) { () => y("https://vulnerabledoma.in/xss_link?url=javascript:\\u{%0A6e}ame"), ].map(t => Test.run(t)) ).then(() => Test.report()); + + let invalidCharsTest = async () => { + + await include("xss/InjectionChecker.js"); + let IC = await XSS.InjectionChecker; + let rx = new IC().invalidCharsRx; + + let x = n => '\\u' + ("0000" + n.toString(16)).slice(-4); + function check(ch) { + eval(`{let _${ch}_}`); + } + let cur = 0x7e; + let fail = false; + while (cur++ < 0xffff) { + let ch = String.fromCharCode(cur); + try { + check(ch); + if (tx.test(ch)) { + console.error(x(cur) + " should not test invalid!"); + fail = true; + } + } catch (e) { + if (!/illegal char/.test(e.message)) continue; + if (!rx.test(ch)) { + console.error(x(cur) + " must test invalid!"); + fail = true; + } + } + } + return !fail; + }; + + Test.run(invalidCharsTest, "InjectionChecker.invalidCharsRx").then(Test.report()); } diff --git a/src/xss/InjectionChecker.js b/src/xss/InjectionChecker.js index 7334ea6..1c99611 100644 --- a/src/xss/InjectionChecker.js +++ b/src/xss/InjectionChecker.js @@ -492,43 +492,8 @@ XSS.InjectionChecker = (async () => { return ret; }, - _createInvalidRanges: function() { - function x(n) { - return '\\u' + ("0000" + n.toString(16)).slice(-4); - } - - let chunks = []; - let first = -1; - let last = -1; - let cur = 0x7e; - while (cur++ <= 0xffff) { - try { - Function("let _" + String.fromCharCode(cur)); - } catch (e) { - if (!/illegal char/.test(e.message)) continue; - if (first == -1) { - first = last = cur; - chunks.push(x(cur)); - continue; - } - if (cur - last == 1) { - last = cur; - continue; - } - - if (last != first) chunks.push(`-${x(last)}`); - chunks.push(x(cur)); - last = first = cur; - } - } - return chunks.join(''); - }, - - get invalidCharsRx() { - let value = new RegExp("^[^\"'`/<>]*[" + this._createInvalidRanges() + "]"); - Object.defineProperty(Object.getPrototypeOf(this), 'invalidCharsRx', {value}); - return value; - }, + // see https://mathiasbynens.be/notes/javascript-identifiers-es6#acceptable-unicode-symbols + invalidCharsRx: /^[^"'`/<>]*[^$_\p{ID_Start}\p{ID_Continue}\u200c\u200d]/u, async checkJSBreak(s) { // Direct script injection breaking JS string literals or comments