-
Notifications
You must be signed in to change notification settings - Fork 13
/
index.js
132 lines (117 loc) · 4.32 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
module.exports = function filter(options) {
options = options || {};
var checkNames = options.checkNames || true;
var typeList = options.typeList || ['object', 'function', 'string'];
var urlBlackList = options.urlBlackList || ['$','{'];
var bodyBlackList = options.bodyBlackList || ['$'];
var methodList = options.methodList || ['GET', 'POST', 'PUT', 'DELETE'];
var urlMessage = options.urlMessage || 'A forbidden expression has been found in URL: ';
var bodyMessage = options.bodyMessage || 'A forbidden expression has been found in form data: ';
var appendFound = options.appendFound || false;
var caseSensitive = (options.caseSensitive === false) ? false : true;
var dispatchToErrorHandler = (options.dispatchToErrorHandler === true) ? true : false;
var errorStatus = 403
var errorCode = "FORBIDDEN_CONTENT"
return function filter(req, res, next) {
/* Only examine the valid methodList */
if (methodList.indexOf(req.method) === -1) {
return next();
}
var found = null;
/* Examining the URL */
if (caseSensitive) {
for (var i = 0; i < urlBlackList.length; i++){
/* The URL in the request might be handled by using 'req.params.id' for 'address/users/:id' by a programmer.
Because of this don't use req.query object instead of req.originalUrl value */
if (req.originalUrl.indexOf(urlBlackList[i]) !== -1) {
found = urlBlackList[i];
break;
}
}
} else {
/* If caseSensitive is `false` convert the originalURL value and bodyBlackList items into lowercase strings then examine them */
var url = req.originalUrl.toLowerCase();
for (var i = 0; i < urlBlackList.length; i++){
if (url.indexOf(urlBlackList[i].toLowerCase()) !== -1) {
found = urlBlackList[i];
break;
}
}
}
if (found) {
if (dispatchToErrorHandler) {
return next({status: errorStatus, code: errorCode, message: urlMessage + (appendFound ? found : "")})
} else {
return res.status(errorStatus).send(urlMessage + (appendFound ? found : ""));
}
}
/* Examining the req.body object If there is a req.body object it must be checked */
if (req.body && Object.keys(req.body).length) {
// // hrstart is used for to calculate the elapsed time
// // https://nodejs.org/api/process.html#process_process_hrtime
// var hrstart = process.hrtime()
jsonToString(req.body, typeList, checkNames, function(str){
/* If caseSensitive is `true` search for bodyBlackList items in combined body string */
if (caseSensitive) {
for (var i = 0; i < bodyBlackList.length; i++){
if (str.indexOf(bodyBlackList[i]) !== -1) {
found = bodyBlackList[i];
break;
}
}
} else {
/* If caseSensitive is `false` convert the string and bodyBlackList items into lowercase strings then examine them */
str = str.toLowerCase()
for (var i = 0; i < bodyBlackList.length; i++){
if (str.indexOf(bodyBlackList[i].toLowerCase()) !== -1) {
found = bodyBlackList[i];
break;
}
}
}
// // hrend is used for to calculate the elapsed time
// var hrend = process.hrtime(hrstart)
// console.log('Execution time (hr): %ds %dms', hrend[0], hrend[1]/1000000)
if (found) {
if (dispatchToErrorHandler) {
return next({status: errorStatus, code: errorCode, message: urlMessage + (appendFound ? found : "")})
} else {
return res.status(errorStatus).send(bodyMessage + (appendFound ? found : ""));
}
}
next();
});
} else {
next();
}
};
};
function jsonToString(json, typeList, checkNames, callback) {
var visitNode = function(obj) {
var type = typeof(obj);
if (obj === null || typeList.indexOf(type) === -1) {
return '';
}
switch (type) {
case 'string':
return obj;
case 'number':
case 'boolean':
case 'undefined':
return String(obj);
default:
return visitObject(obj);
}
}
var visitObject = function(obj) {
var buffer = '';
var keys = Object.keys(obj);
var includeKey = checkNames && !Array.isArray(obj);
for (var i = 0; i < keys.length; ++i) {
var key = keys[i];
buffer += (includeKey ? key : '') + visitNode(obj[key]);
}
return buffer;
}
return callback(visitNode(json));
}