Skip to content

Commit eca63a7

Browse files
authored
Merge pull request #10 from jeffrey-pinyan-ithreat/master
fixed regexes to avoid ReDoS attacks
2 parents 5d23c14 + d8b5e6b commit eca63a7

File tree

3 files changed

+38
-35
lines changed

3 files changed

+38
-35
lines changed

.npmignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
.travis.yml
2+
redos.js
23
test.js

index.js

Lines changed: 17 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,14 @@
22

33
var isWindows = process.platform === 'win32';
44

5-
// Regex to split a windows path into three parts: [*, device, slash,
6-
// tail] windows-only
7-
var splitDeviceRe =
8-
/^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/;
9-
10-
// Regex to split the tail part of the above into [*, dir, basename, ext]
11-
var splitTailRe =
12-
/^([\s\S]*?)((?:\.{1,2}|[^\\\/]+?|)(\.[^.\/\\]*|))(?:[\\\/]*)$/;
5+
// Regex to split a windows path into into [dir, root, basename, name, ext]
6+
var splitWindowsRe =
7+
/^(((?:[a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?[\\\/]?)(?:[^\\\/]*[\\\/])*)((\.{1,2}|[^\\\/]+?|)(\.[^.\/\\]*|))[\\\/]*$/;
138

149
var win32 = {};
1510

16-
// Function to split a filename into [root, dir, basename, ext]
1711
function win32SplitPath(filename) {
18-
// Separate device+slash from tail
19-
var result = splitDeviceRe.exec(filename),
20-
device = (result[1] || '') + (result[2] || ''),
21-
tail = result[3] || '';
22-
// Split the tail into dir, basename and extension
23-
var result2 = splitTailRe.exec(tail),
24-
dir = result2[1],
25-
basename = result2[2],
26-
ext = result2[3];
27-
return [device, dir, basename, ext];
12+
return splitWindowsRe.exec(filename).slice(1);
2813
}
2914

3015
win32.parse = function(pathString) {
@@ -34,24 +19,24 @@ win32.parse = function(pathString) {
3419
);
3520
}
3621
var allParts = win32SplitPath(pathString);
37-
if (!allParts || allParts.length !== 4) {
22+
if (!allParts || allParts.length !== 5) {
3823
throw new TypeError("Invalid path '" + pathString + "'");
3924
}
4025
return {
41-
root: allParts[0],
42-
dir: allParts[0] + allParts[1].slice(0, -1),
26+
root: allParts[1],
27+
dir: allParts[0] === allParts[1] ? allParts[0] : allParts[0].slice(0, -1),
4328
base: allParts[2],
44-
ext: allParts[3],
45-
name: allParts[2].slice(0, allParts[2].length - allParts[3].length)
29+
ext: allParts[4],
30+
name: allParts[3]
4631
};
4732
};
4833

4934

5035

51-
// Split a filename into [root, dir, basename, ext], unix version
36+
// Split a filename into [dir, root, basename, name, ext], unix version
5237
// 'root' is just a slash, or nothing.
5338
var splitPathRe =
54-
/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
39+
/^((\/?)(?:[^\/]*\/)*)((\.{1,2}|[^\/]+?|)(\.[^.\/]*|))[\/]*$/;
5540
var posix = {};
5641

5742

@@ -67,19 +52,16 @@ posix.parse = function(pathString) {
6752
);
6853
}
6954
var allParts = posixSplitPath(pathString);
70-
if (!allParts || allParts.length !== 4) {
55+
if (!allParts || allParts.length !== 5) {
7156
throw new TypeError("Invalid path '" + pathString + "'");
7257
}
73-
allParts[1] = allParts[1] || '';
74-
allParts[2] = allParts[2] || '';
75-
allParts[3] = allParts[3] || '';
76-
58+
7759
return {
78-
root: allParts[0],
79-
dir: allParts[0] + allParts[1].slice(0, -1),
60+
root: allParts[1],
61+
dir: allParts[0].slice(0, -1),
8062
base: allParts[2],
81-
ext: allParts[3],
82-
name: allParts[2].slice(0, allParts[2].length - allParts[3].length)
63+
ext: allParts[4],
64+
name: allParts[3],
8365
};
8466
};
8567

redos.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
var pathParse = require('.');
2+
3+
function build_attack(n) {
4+
var ret = ""
5+
for (var i = 0; i < n; i++) {
6+
ret += "/"
7+
}
8+
return ret + "◎";
9+
}
10+
11+
for(var i = 1; i <= 5000000; i++) {
12+
if (i % 10000 == 0) {
13+
var time = Date.now();
14+
var attack_str = build_attack(i)
15+
pathParse.posix(attack_str);
16+
pathParse.win32(attack_str);
17+
var time_cost = Date.now() - time;
18+
console.log("attack_str.length: " + attack_str.length + ": " + time_cost+" ms")
19+
}
20+
}

0 commit comments

Comments
 (0)