73 lines
1.5 KiB
JavaScript
73 lines
1.5 KiB
JavaScript
|
// Exports an Analyzer subclass
|
||
|
|
||
|
const regexpTree = require("regexp-tree");
|
||
|
const analyzer = require("./analyzer");
|
||
|
|
||
|
class HeuristicAnalyzer extends analyzer.Analyzer {
|
||
|
constructor(analyzerOptions) {
|
||
|
super(analyzerOptions);
|
||
|
}
|
||
|
|
||
|
isVulnerable(regExp) {
|
||
|
// Heuristic #1: Star height > 1
|
||
|
const starHeight = this._measureStarHeight(regExp);
|
||
|
if (starHeight > 1) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Heuristic #2: # repetitions > limit
|
||
|
// TODO This is a poor heuristic
|
||
|
const nRepetitions = this._measureRepetitions(regExp);
|
||
|
if (nRepetitions > this.options.heuristic_replimit) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
genAttackString(regExp) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
_measureStarHeight(regExp) {
|
||
|
let currentStarHeight = 0;
|
||
|
let maxObservedStarHeight = 0;
|
||
|
|
||
|
const ast = regexpTree.parse(regExp);
|
||
|
|
||
|
regexpTree.traverse(ast, {
|
||
|
Repetition: {
|
||
|
pre({ node }) {
|
||
|
currentStarHeight++;
|
||
|
if (maxObservedStarHeight < currentStarHeight) {
|
||
|
maxObservedStarHeight = currentStarHeight;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
post({ node }) {
|
||
|
currentStarHeight--;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
return maxObservedStarHeight;
|
||
|
}
|
||
|
|
||
|
_measureRepetitions(regExp) {
|
||
|
let nRepetitions = 0;
|
||
|
|
||
|
const ast = regexpTree.parse(regExp);
|
||
|
regexpTree.traverse(ast, {
|
||
|
Repetition: {
|
||
|
pre({ node }) {
|
||
|
nRepetitions++;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
return nRepetitions;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
module.exports = HeuristicAnalyzer;
|