@contrast/agent 4.23.0 → 4.23.1
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/core/express/index.js +75 -29
- package/lib/protect/sinks/mongodb.js +77 -65
- package/package.json +1 -1
|
@@ -59,6 +59,7 @@ class ExpressFramework {
|
|
|
59
59
|
// Express middleware error handler.
|
|
60
60
|
this.errorHandler = ExpressFramework.ContrastErrorHandler.bind(this);
|
|
61
61
|
moduleHook.resolve({ name: 'express' }, this.hookExpress.bind(this));
|
|
62
|
+
moduleHook.resolve({ name: 'body-parser' }, this.hookBodyParser.bind(this));
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
/**
|
|
@@ -227,6 +228,80 @@ class ExpressFramework {
|
|
|
227
228
|
agentEmitter.on(HTTP_EVENTS.SERVER_LISTEN, this.onServerListen.bind(this));
|
|
228
229
|
}
|
|
229
230
|
|
|
231
|
+
hookBodyParser(bodyParser) {
|
|
232
|
+
const instrumentation = this;
|
|
233
|
+
const origBodyParser = bodyParser;
|
|
234
|
+
|
|
235
|
+
const { json: origJson, raw: origRaw, text: origText, urlencoded: origUrlencoded } = bodyParser;
|
|
236
|
+
const fnArr = [
|
|
237
|
+
{
|
|
238
|
+
key: 'json',
|
|
239
|
+
original: origJson,
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
key: 'raw',
|
|
243
|
+
original: origRaw,
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
key: 'text',
|
|
247
|
+
original: origText,
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
key: 'urlencoded',
|
|
251
|
+
original: origUrlencoded,
|
|
252
|
+
}
|
|
253
|
+
];
|
|
254
|
+
|
|
255
|
+
bodyParser = function bodyParser(...args) {
|
|
256
|
+
const parser = origBodyParser(...args);
|
|
257
|
+
const hookedParser = function(req, res, next) {
|
|
258
|
+
parser(req, res, instrumentation.contrastNext(req, res, next, 'bodyParser'));
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
Object.defineProperty(hookedParser, 'name', {
|
|
262
|
+
value: 'bodyParser'
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
return hookedParser;
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
fnArr.forEach((fn) => {
|
|
269
|
+
const fnName = `bodyParser.${fn.key}`;
|
|
270
|
+
function contrastHooked(...args) {
|
|
271
|
+
const parser = fn.original(...args);
|
|
272
|
+
const hookedParser = function (req, res, next) {
|
|
273
|
+
parser(req, res, instrumentation.contrastNext(req, res, next, fnName));
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
Object.defineProperty(hookedParser, 'name', {
|
|
277
|
+
value: `${fn.key}Parser`
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
return hookedParser;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
Object.defineProperty(bodyParser, fn.key, {
|
|
284
|
+
configurable: true,
|
|
285
|
+
enumerable: true,
|
|
286
|
+
get: () => contrastHooked,
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
return bodyParser;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
contrastNext(req, res, origNext, fnName) {
|
|
294
|
+
return function next() {
|
|
295
|
+
if (fnName == 'bodyParser.json') {
|
|
296
|
+
agentEmitter.emit(EVENTS.BODY_PARSED, req, res, INPUT_TYPES.JSON_VALUE);
|
|
297
|
+
} else {
|
|
298
|
+
agentEmitter.emit(EVENTS.BODY_PARSED, req, res, INPUT_TYPES.BODY);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
origNext();
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
230
305
|
onServerListen(args, server) {
|
|
231
306
|
if (!this.serversSeen.has(server)) {
|
|
232
307
|
logger.debug('ignore server.listen: non-express handler');
|
|
@@ -316,35 +391,6 @@ class ExpressFramework {
|
|
|
316
391
|
next();
|
|
317
392
|
}, 'multerMiddleware');
|
|
318
393
|
|
|
319
|
-
// ... body-parser ...............................................
|
|
320
|
-
this.useAfter(function ContrastRawBodyParsed(req, res, next) {
|
|
321
|
-
agentEmitter.emit(EVENTS.BODY_PARSED, req, res, INPUT_TYPES.BODY);
|
|
322
|
-
next();
|
|
323
|
-
}, 'rawParser');
|
|
324
|
-
|
|
325
|
-
// ... bodyParser in Sails Framework ............................
|
|
326
|
-
this.useAfter(function ContrastBodyParsed(req, res, next) {
|
|
327
|
-
if (req._sails && req.body) {
|
|
328
|
-
agentEmitter.emit(EVENTS.BODY_PARSED, req, res, INPUT_TYPES.BODY);
|
|
329
|
-
}
|
|
330
|
-
next();
|
|
331
|
-
}, '_parseHTTPBody');
|
|
332
|
-
|
|
333
|
-
this.useAfter(function ContrastTextBodyParsed(req, res, next) {
|
|
334
|
-
agentEmitter.emit(EVENTS.BODY_PARSED, req, res, INPUT_TYPES.BODY);
|
|
335
|
-
next();
|
|
336
|
-
}, 'textParser');
|
|
337
|
-
|
|
338
|
-
this.useAfter(function ContrastBodyParsed(req, res, next) {
|
|
339
|
-
agentEmitter.emit(EVENTS.BODY_PARSED, req, res, INPUT_TYPES.BODY);
|
|
340
|
-
next();
|
|
341
|
-
}, 'urlencodedParser');
|
|
342
|
-
|
|
343
|
-
this.useAfter(function ContrastJSONParsed(req, res, next) {
|
|
344
|
-
agentEmitter.emit(EVENTS.BODY_PARSED, req, res, INPUT_TYPES.JSON_VALUE);
|
|
345
|
-
next();
|
|
346
|
-
}, 'jsonParser');
|
|
347
|
-
|
|
348
394
|
// ... cookie-parser .............................................
|
|
349
395
|
this.useAfter(function ContrastCookiesParsed(req, res, next) {
|
|
350
396
|
agentEmitter.emit(
|
|
@@ -16,13 +16,11 @@ Copyright: 2022 Contrast Security, Inc
|
|
|
16
16
|
|
|
17
17
|
const _ = require('lodash');
|
|
18
18
|
const semver = require('semver');
|
|
19
|
-
const constants = require('../../constants');
|
|
20
|
-
const BaseSensor = require('../../hooks/frameworks/base');
|
|
21
19
|
const patcher = require('../../hooks/patcher');
|
|
22
|
-
const
|
|
20
|
+
const BaseSensor = require('../../hooks/frameworks/base');
|
|
21
|
+
const { PATCH_TYPES, SINK_TYPES } = require('../../constants');
|
|
23
22
|
const { emitSinkEvent } = require('../../hooks/frameworks/common');
|
|
24
23
|
|
|
25
|
-
const { SINK_TYPES } = constants;
|
|
26
24
|
const ID = 'mongodb';
|
|
27
25
|
|
|
28
26
|
function getCursorQueryData(args, version) {
|
|
@@ -61,84 +59,98 @@ class MongoDBSensor extends BaseSensor {
|
|
|
61
59
|
}
|
|
62
60
|
|
|
63
61
|
install({ ModuleHook }) {
|
|
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
|
-
|
|
62
|
+
const v4MethodsWithFilter = [
|
|
63
|
+
'updateOne',
|
|
64
|
+
'replaceOne',
|
|
65
|
+
'updateMany',
|
|
66
|
+
'deleteOne',
|
|
67
|
+
'deleteMany',
|
|
68
|
+
'findOneAndDelete',
|
|
69
|
+
'findOneAndReplace',
|
|
70
|
+
'findOneAndUpdate',
|
|
71
|
+
'countDocuments',
|
|
72
|
+
'count',
|
|
73
|
+
'distinct',
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
ModuleHook.resolve({ name: ID, version: '<4.0.0' }, (mongodb, { version }) => {
|
|
77
|
+
['command', 'cursor'].forEach(method => {
|
|
78
|
+
patcher.patch(mongodb.CoreServer.prototype, method, {
|
|
79
|
+
alwaysRun: true,
|
|
80
|
+
name: `mongodb.CoreServer.prototype.${method}`,
|
|
81
|
+
patchType: PATCH_TYPES.PROTECT_SINK,
|
|
82
|
+
pre: (wrapCtx) => {
|
|
83
|
+
emitSinkEvent(
|
|
84
|
+
getCursorQueryData(wrapCtx.args, version),
|
|
85
|
+
SINK_TYPES.NOSQL_QUERY,
|
|
86
|
+
ID
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
91
90
|
});
|
|
92
91
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
emitSinkEvent(eData, SINK_TYPES.NOSQL_QUERY, ID);
|
|
92
|
+
['remove', 'update'].forEach(method => {
|
|
93
|
+
patcher.patch(mongodb.CoreServer.prototype, method, {
|
|
94
|
+
alwaysRun: true,
|
|
95
|
+
name: 'mongodb.CoreServer.prototype.remove',
|
|
96
|
+
patchType: PATCH_TYPES.PROTECT_SINK,
|
|
97
|
+
pre: (wrapCtx) => {
|
|
98
|
+
const ops = Array.isArray(wrapCtx.args[1]) ? wrapCtx.args[1] : [wrapCtx.args[1]];
|
|
99
|
+
|
|
100
|
+
for (const op of ops) {
|
|
101
|
+
const eData = getOpQueryData(op);
|
|
102
|
+
if (eData) {
|
|
103
|
+
emitSinkEvent(eData, SINK_TYPES.NOSQL_QUERY, ID);
|
|
104
|
+
}
|
|
107
105
|
}
|
|
108
106
|
}
|
|
109
|
-
}
|
|
107
|
+
});
|
|
110
108
|
});
|
|
111
109
|
|
|
112
|
-
|
|
113
|
-
patcher.patch(mongodb.CoreServer.prototype, 'update', {
|
|
110
|
+
patcher.patch(mongodb.Db.prototype, 'eval', {
|
|
114
111
|
alwaysRun: true,
|
|
115
|
-
name: 'mongodb.
|
|
112
|
+
name: 'mongodb.Db.prototype.eval',
|
|
116
113
|
patchType: PATCH_TYPES.PROTECT_SINK,
|
|
117
|
-
pre: (
|
|
118
|
-
|
|
119
|
-
? data.args[1]
|
|
120
|
-
: [data.args[1]];
|
|
121
|
-
|
|
122
|
-
for (const op of ops) {
|
|
123
|
-
const eData = getOpQueryData(op);
|
|
124
|
-
if (eData) {
|
|
125
|
-
emitSinkEvent(eData, SINK_TYPES.NOSQL_QUERY, ID);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
114
|
+
pre: (wrapCtx) => {
|
|
115
|
+
emitSinkEvent(wrapCtx.args[0], SINK_TYPES.NOSQL_QUERY, ID);
|
|
128
116
|
}
|
|
129
117
|
});
|
|
118
|
+
});
|
|
130
119
|
|
|
131
|
-
|
|
132
|
-
|
|
120
|
+
ModuleHook.resolve({ name: ID, version: '>=4.0.0' }, (mongodb) => {
|
|
121
|
+
v4MethodsWithFilter.forEach((method) => {
|
|
122
|
+
patcher.patch(mongodb.Collection.prototype, method, {
|
|
123
|
+
alwaysRun: true,
|
|
124
|
+
name: `mongodb.Collection.prototype.${method}`,
|
|
125
|
+
patchType: PATCH_TYPES.PROTECT_SINK,
|
|
126
|
+
pre: (wrapCtx) => {
|
|
127
|
+
const value = typeof wrapCtx.args[0] == 'function' ? null : wrapCtx.args[0];
|
|
128
|
+
emitSinkEvent(value, SINK_TYPES.NOSQL_QUERY, ID);
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
patcher.patch(mongodb.Db.prototype, 'command', {
|
|
133
134
|
alwaysRun: true,
|
|
134
|
-
name: 'mongodb.Db.prototype',
|
|
135
|
+
name: 'mongodb.Db.prototype.command',
|
|
135
136
|
patchType: PATCH_TYPES.PROTECT_SINK,
|
|
136
|
-
pre: (
|
|
137
|
-
|
|
137
|
+
pre: (wrapCtx) => {
|
|
138
|
+
const value = wrapCtx.args[0] && wrapCtx.args[0].filter;
|
|
139
|
+
emitSinkEvent(value, SINK_TYPES.NOSQL_QUERY, ID);
|
|
138
140
|
}
|
|
139
141
|
});
|
|
140
142
|
});
|
|
141
143
|
|
|
144
|
+
ModuleHook.resolve({ name: ID, file: 'lib/cursor/find_cursor', version: '>=4.0.0' }, (cursor) => patcher.patch(cursor, 'FindCursor', {
|
|
145
|
+
alwaysRun: true,
|
|
146
|
+
name: 'mongodb.FindCursor',
|
|
147
|
+
patchType: PATCH_TYPES.PROTECT_SINK,
|
|
148
|
+
pre: (wrapCtx) => {
|
|
149
|
+
const value = wrapCtx.args[2];
|
|
150
|
+
emitSinkEvent(value, SINK_TYPES.NOSQL_QUERY, ID);
|
|
151
|
+
}
|
|
152
|
+
}));
|
|
153
|
+
|
|
142
154
|
return this;
|
|
143
155
|
}
|
|
144
156
|
}
|