@contrast/protect 1.2.2 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cli-rewriter.js +15 -0
- package/lib/error-handlers/constants.js +15 -0
- package/lib/error-handlers/index.js +17 -0
- package/lib/error-handlers/install/express4.js +90 -0
- package/lib/error-handlers/install/fastify3.js +15 -0
- package/lib/error-handlers/install/koa2.js +15 -0
- package/lib/esm-loader.mjs +15 -0
- package/lib/index.d.ts +145 -19
- package/lib/index.js +15 -0
- package/lib/input-analysis/constants.js +20 -0
- package/lib/input-analysis/handlers.js +33 -10
- package/lib/input-analysis/index.js +36 -3
- package/lib/input-analysis/install/body-parser1.js +130 -0
- package/lib/input-analysis/install/cookie-parser1.js +82 -0
- package/lib/input-analysis/install/express4.js +108 -0
- package/lib/input-analysis/install/fastify3.js +47 -19
- package/lib/input-analysis/install/formidable1.js +73 -0
- package/lib/input-analysis/install/http.js +18 -1
- package/lib/input-analysis/install/koa-body5.js +68 -0
- package/lib/input-analysis/install/koa-bodyparser4.js +68 -0
- package/lib/input-analysis/install/koa2.js +26 -25
- package/lib/input-analysis/install/multer1.js +89 -0
- package/lib/input-analysis/install/qs6.js +61 -0
- package/lib/input-analysis/install/universal-cookie4.js +56 -0
- package/lib/input-tracing/constants.js +15 -0
- package/lib/input-tracing/handlers/index.js +154 -59
- package/lib/input-tracing/index.js +17 -0
- package/lib/input-tracing/install/child-process.js +16 -1
- package/lib/input-tracing/install/fs.js +17 -2
- package/lib/input-tracing/install/mongodb.js +233 -0
- package/lib/input-tracing/install/mysql.js +18 -2
- package/lib/input-tracing/install/postgres.js +15 -0
- package/lib/input-tracing/install/sequelize.js +15 -0
- package/lib/input-tracing/install/sqlite3.js +15 -0
- package/lib/make-response-blocker.js +15 -0
- package/lib/make-source-context.js +18 -0
- package/lib/security-exception.js +15 -0
- package/lib/throw-security-exception.js +17 -6
- package/lib/utils.js +14 -18
- package/package.json +8 -8
- package/lib/input-analysis/install/co-body.js +0 -51
- package/lib/input-analysis/install/cookie-parser.js +0 -48
- package/lib/input-analysis/install/formidable.js +0 -53
- package/lib/input-analysis/install/multer.js +0 -52
- package/lib/input-analysis/install/qs.js +0 -40
- package/lib/input-analysis/install/universal-cookie.js +0 -34
- package/lib/input-tracing/handlers/nosql-injection-mongo.js +0 -48
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
module.exports = (core) => {
|
|
4
|
-
const {
|
|
5
|
-
depHooks,
|
|
6
|
-
patcher,
|
|
7
|
-
logger,
|
|
8
|
-
scopes: { sources },
|
|
9
|
-
protect: { inputAnalysis },
|
|
10
|
-
} = core;
|
|
11
|
-
|
|
12
|
-
return {
|
|
13
|
-
// Patch `formidable`
|
|
14
|
-
install() {
|
|
15
|
-
depHooks.resolve({ name: 'formidable' }, (formidable) => {
|
|
16
|
-
formidable.IncomingForm.prototype.parse = patcher.patch(formidable.IncomingForm.prototype.parse, {
|
|
17
|
-
name: 'Formidable.IncomingForm.prototype.parse',
|
|
18
|
-
patchType: 'framework-patch',
|
|
19
|
-
pre(data) {
|
|
20
|
-
const origCb = data.args[1];
|
|
21
|
-
|
|
22
|
-
function hookedCb(...cbArgs) {
|
|
23
|
-
const sourceContext = sources.getStore()?.protect;
|
|
24
|
-
const [, fields, files] = cbArgs;
|
|
25
|
-
|
|
26
|
-
if (!sourceContext) {
|
|
27
|
-
logger.debug('source context not available in `formidable` hook');
|
|
28
|
-
} else {
|
|
29
|
-
if (fields) {
|
|
30
|
-
sourceContext.parsedBody = fields;
|
|
31
|
-
inputAnalysis.handleParsedBody(sourceContext, fields);
|
|
32
|
-
}
|
|
33
|
-
if (files) {
|
|
34
|
-
logger.debug('Check for vulnerable filename upload nyi');
|
|
35
|
-
// CHECK FILENAME - NYI
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (origCb && typeof origCb === 'function') {
|
|
40
|
-
// Should we explicitly run in the current source context?
|
|
41
|
-
origCb.apply(this, cbArgs);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
data.args[1] = hookedCb;
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
return formidable;
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
};
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
module.exports = (core) => {
|
|
4
|
-
const {
|
|
5
|
-
depHooks,
|
|
6
|
-
patcher,
|
|
7
|
-
logger,
|
|
8
|
-
scopes: { sources },
|
|
9
|
-
protect: { inputAnalysis },
|
|
10
|
-
} = core;
|
|
11
|
-
|
|
12
|
-
return {
|
|
13
|
-
// Patch `multer`
|
|
14
|
-
install() {
|
|
15
|
-
depHooks.resolve({ name: 'multer', file: 'lib/make-middleware.js' }, (multerMakeMiddleware) => patcher.patch(multerMakeMiddleware, {
|
|
16
|
-
name: 'multer.make-middleware',
|
|
17
|
-
patchType: 'framework-patch',
|
|
18
|
-
post(data) {
|
|
19
|
-
data.result = patcher.patch(data.result, {
|
|
20
|
-
name: 'multerMiddleware',
|
|
21
|
-
patchType: 'framework-patch',
|
|
22
|
-
pre(data) {
|
|
23
|
-
const [req, , origNext] = data.args;
|
|
24
|
-
|
|
25
|
-
async function contrastNext() {
|
|
26
|
-
|
|
27
|
-
const sourceContext = sources.getStore()?.protect;
|
|
28
|
-
|
|
29
|
-
if (!sourceContext) {
|
|
30
|
-
logger.debug('source context not available in `multer` hook');
|
|
31
|
-
} else {
|
|
32
|
-
if (req.body) {
|
|
33
|
-
sourceContext.parsedBody = req.body;
|
|
34
|
-
inputAnalysis.handleParsedBody(sourceContext, req.body);
|
|
35
|
-
}
|
|
36
|
-
if (req.file || req.files) {
|
|
37
|
-
logger.debug('Check for vulnerable filename upload nyi');
|
|
38
|
-
// CHECK FILENAME - NYI
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
await origNext();
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
data.args[2] = contrastNext;
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
}));
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
};
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
module.exports = (core) => {
|
|
4
|
-
const {
|
|
5
|
-
depHooks,
|
|
6
|
-
patcher,
|
|
7
|
-
logger,
|
|
8
|
-
scopes: { sources },
|
|
9
|
-
protect: { inputAnalysis },
|
|
10
|
-
} = core;
|
|
11
|
-
|
|
12
|
-
return {
|
|
13
|
-
// Patch `qs`
|
|
14
|
-
install() {
|
|
15
|
-
depHooks.resolve({ name: 'qs' },
|
|
16
|
-
(qs) => patcher.patch(qs, 'parse', {
|
|
17
|
-
name: 'qs',
|
|
18
|
-
patchType: 'framework-patch',
|
|
19
|
-
post({ args, result }) {
|
|
20
|
-
if (result && Object.keys(result).length) {
|
|
21
|
-
const sourceContext = sources.getStore()?.protect;
|
|
22
|
-
|
|
23
|
-
if (!sourceContext) {
|
|
24
|
-
logger.debug('source context not available in `qs` hook');
|
|
25
|
-
|
|
26
|
-
// We need to run analysis for the `qs` result only when it's used as a query parser.
|
|
27
|
-
// `qs` is used also for parsing bodies, but these cases we handle individually with
|
|
28
|
-
// the respective library that's using it (e.g. `formidable`, `co-body`) because in
|
|
29
|
-
// some cases its use is optional and we cannot rely on it.
|
|
30
|
-
} else if (sourceContext.reqData?.queries === args[0]) {
|
|
31
|
-
sourceContext.parsedQuery = result;
|
|
32
|
-
inputAnalysis.handleQueryParams(sourceContext, result);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
})
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
module.exports = (core) => {
|
|
4
|
-
const {
|
|
5
|
-
depHooks,
|
|
6
|
-
patcher,
|
|
7
|
-
logger,
|
|
8
|
-
scopes: { sources },
|
|
9
|
-
protect: { inputAnalysis },
|
|
10
|
-
} = core;
|
|
11
|
-
|
|
12
|
-
return {
|
|
13
|
-
// Patch `universal-cookie` package
|
|
14
|
-
install() {
|
|
15
|
-
depHooks.resolve({ name: 'universal-cookie', file: 'cjs/utils.js' }, (uCookieUtils) => patcher.patch(uCookieUtils, 'parseCookies', {
|
|
16
|
-
name: 'universal-cookie.utils',
|
|
17
|
-
patchType: 'framework-patch',
|
|
18
|
-
post({ result }) {
|
|
19
|
-
if (result && Object.keys(result).length) {
|
|
20
|
-
const sourceContext = sources.getStore()?.protect;
|
|
21
|
-
|
|
22
|
-
if (!sourceContext) {
|
|
23
|
-
logger.debug('source context not available in `universal-cookie` hook');
|
|
24
|
-
} else {
|
|
25
|
-
sourceContext.parsedCookies = result;
|
|
26
|
-
inputAnalysis.handleCookies(sourceContext, result);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
})
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
};
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/* c8 ignore start */
|
|
4
|
-
// this is just the general structure of how to handle mongo sinks
|
|
5
|
-
const util = require('util');
|
|
6
|
-
|
|
7
|
-
const { simpleTraverse } = require('../../utils');
|
|
8
|
-
|
|
9
|
-
function mongoSink(results, sinkContext) {
|
|
10
|
-
if (typeof sinkContext.value === 'object') {
|
|
11
|
-
return handleObjectValue(results, sinkContext.value);
|
|
12
|
-
} else if (typeof sinkContext.value === 'string') {
|
|
13
|
-
return handleStringValue(results, sinkContext.value);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
return null;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function handleObjectValue(results, object) {
|
|
20
|
-
for (const result of results) {
|
|
21
|
-
simpleTraverse(object, function(path, type, value) {
|
|
22
|
-
if (type !== 'Key') {
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
// the result value is the key that was found
|
|
26
|
-
if (result.value === value) {
|
|
27
|
-
// does the object at this path equal the user input?
|
|
28
|
-
let obj = object;
|
|
29
|
-
for (const p of path) {
|
|
30
|
-
obj = obj[p];
|
|
31
|
-
}
|
|
32
|
-
obj = obj[value];
|
|
33
|
-
// does the found object in the query equal the saved object?
|
|
34
|
-
if (util.isDeepStrictEqual(obj, object)) {
|
|
35
|
-
//
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function handleStringValue(results, string) {
|
|
43
|
-
// nyi
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
module.exports = mongoSink;
|
|
47
|
-
|
|
48
|
-
/* c8 ignore stop */
|