diff --git a/src/nscl b/src/nscl index b0b355d..2bf555f 160000 --- a/src/nscl +++ b/src/nscl @@ -1 +1 @@ -Subproject commit b0b355de528b11b8ae641b429f3442fe19bbff67 +Subproject commit 2bf555fca3aa803fa72fd43ef94403aefb1254a5 diff --git a/src/xss/InjectionChecker.js b/src/xss/InjectionChecker.js index 3cfaa28..5dbf57b 100644 --- a/src/xss/InjectionChecker.js +++ b/src/xss/InjectionChecker.js @@ -49,7 +49,7 @@ XSS.InjectionChecker = (async () => { "|\\b(?:" + IC_WINDOW_OPENER_PATTERN + ")\\b[^]+\\b(?:" + IC_EVENT_PATTERN + ")[^]*="; function InjectionChecker() { - this.timing = new Timing(); + this.timing = new Timing(20); this.reset(); } InjectionChecker.prototype = { @@ -492,8 +492,44 @@ XSS.InjectionChecker = (async () => { return ret; }, - // see https://mathiasbynens.be/notes/javascript-identifiers-es6#acceptable-unicode-symbols - invalidCharsRx: /^[^"'`/<>]*[^$_\p{ID_Start}\p{ID_Continue}\u200c\u200d]/u, + _createInvalidRanges: function() { + function x(n) { + return '\\u' + ("0000" + n.toString(16)).slice(-4); + } + + let chunks = []; + let first = -1; + let last = -1; + let cur = 0x7e; + let close = () => { if (last != first) chunks.push(`-${x(last)}`); } + 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; + } + close(); + chunks.push(x(cur)); + last = first = cur; + } + } + close(); + return chunks.join(''); + }, + + get invalidCharsRx() { + let value = new RegExp("^[^\"'`/<>]*[" + this._createInvalidRanges() + "]"); + Object.defineProperty(Object.getPrototypeOf(this), 'invalidCharsRx', {value}); + return value; + }, async checkJSBreak(s) { // Direct script injection breaking JS string literals or comments