@newrelic/security-agent 0.0.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.
Files changed (87) hide show
  1. package/CHANGELOG.md +0 -0
  2. package/CONTRIBUTING.md +23 -0
  3. package/LICENSE +43 -0
  4. package/README.md +98 -0
  5. package/THIRD_PARTY_NOTICES.md +2909 -0
  6. package/index.js +24 -0
  7. package/lib/instrumentation-security/core/constants.js +66 -0
  8. package/lib/instrumentation-security/core/event-constants.js +49 -0
  9. package/lib/instrumentation-security/core/request-manager.js +73 -0
  10. package/lib/instrumentation-security/core/route-manager.js +30 -0
  11. package/lib/instrumentation-security/core/sec-trace.js +134 -0
  12. package/lib/instrumentation-security/core/sec-utils.js +212 -0
  13. package/lib/instrumentation-security/core/security-metadata.js +34 -0
  14. package/lib/instrumentation-security/core/stack-trace.js +156 -0
  15. package/lib/instrumentation-security/hooks/director/nr-director.js +98 -0
  16. package/lib/instrumentation-security/hooks/express/nr-express.js +106 -0
  17. package/lib/instrumentation-security/hooks/fastify/nr-fastify.js +155 -0
  18. package/lib/instrumentation-security/hooks/fs/nr-fs.js +391 -0
  19. package/lib/instrumentation-security/hooks/hapi/nr-hapi.js +131 -0
  20. package/lib/instrumentation-security/hooks/http/nr-http.js +461 -0
  21. package/lib/instrumentation-security/hooks/koa/@koa/nr-@koa-router.js +110 -0
  22. package/lib/instrumentation-security/hooks/ldap/nr-ldap.js +81 -0
  23. package/lib/instrumentation-security/hooks/mongodb/common.js +239 -0
  24. package/lib/instrumentation-security/hooks/mongodb/constants.js +91 -0
  25. package/lib/instrumentation-security/hooks/mongodb/nr-mongodb.js +49 -0
  26. package/lib/instrumentation-security/hooks/mongodb/v2-mongo.js +91 -0
  27. package/lib/instrumentation-security/hooks/mongodb/v3-mongo.js +36 -0
  28. package/lib/instrumentation-security/hooks/mongodb/v4-mongo.js +17 -0
  29. package/lib/instrumentation-security/hooks/mysql/nr-mysql.js +232 -0
  30. package/lib/instrumentation-security/hooks/native/nr-childProcess.js +131 -0
  31. package/lib/instrumentation-security/hooks/postgres/nr-postgres.js +131 -0
  32. package/lib/instrumentation-security/hooks/require/nr-require.js +93 -0
  33. package/lib/instrumentation-security/hooks/restify/nr-restify.js +104 -0
  34. package/lib/instrumentation-security/hooks/xpath/nr-xpath.js +91 -0
  35. package/lib/instrumentation-security/index.js +171 -0
  36. package/lib/nr-security-agent/index.js +170 -0
  37. package/lib/nr-security-agent/lib/core/Auth-headers.js +58 -0
  38. package/lib/nr-security-agent/lib/core/ContainerProperties.js +42 -0
  39. package/lib/nr-security-agent/lib/core/ECSProperties.js +34 -0
  40. package/lib/nr-security-agent/lib/core/FuzzFailEvent.js +27 -0
  41. package/lib/nr-security-agent/lib/core/LinkingMetadata.js +21 -0
  42. package/lib/nr-security-agent/lib/core/LogMessage.js +47 -0
  43. package/lib/nr-security-agent/lib/core/PodProperties.js +36 -0
  44. package/lib/nr-security-agent/lib/core/Policy.js +105 -0
  45. package/lib/nr-security-agent/lib/core/agent-status.js +56 -0
  46. package/lib/nr-security-agent/lib/core/agent.js +146 -0
  47. package/lib/nr-security-agent/lib/core/applicationinfo.js +634 -0
  48. package/lib/nr-security-agent/lib/core/commonUtils.js +411 -0
  49. package/lib/nr-security-agent/lib/core/connections/aws-lambda-client.js +55 -0
  50. package/lib/nr-security-agent/lib/core/connections/restclient.js +20 -0
  51. package/lib/nr-security-agent/lib/core/connections/websocket/index.js +25 -0
  52. package/lib/nr-security-agent/lib/core/connections/websocket/response/collecotor-policy-error-handler.js +18 -0
  53. package/lib/nr-security-agent/lib/core/connections/websocket/response/collector-policy-handler.js +20 -0
  54. package/lib/nr-security-agent/lib/core/connections/websocket/response/fuzz-request-handler.js +171 -0
  55. package/lib/nr-security-agent/lib/core/connections/websocket/response/index.js +47 -0
  56. package/lib/nr-security-agent/lib/core/connections/websocket/response/no-op-handler.js +12 -0
  57. package/lib/nr-security-agent/lib/core/connections/websocket/response/startup-handshake-handler.js +27 -0
  58. package/lib/nr-security-agent/lib/core/connections/websocket/response/unsupported-agent-handler.js +18 -0
  59. package/lib/nr-security-agent/lib/core/connections/websocket/response/ws-reconnect.js +14 -0
  60. package/lib/nr-security-agent/lib/core/connections/websocket/websocket.js +443 -0
  61. package/lib/nr-security-agent/lib/core/event.js +186 -0
  62. package/lib/nr-security-agent/lib/core/health-check.js +159 -0
  63. package/lib/nr-security-agent/lib/core/json-file-handler.js +66 -0
  64. package/lib/nr-security-agent/lib/core/jsonValidator.js +149 -0
  65. package/lib/nr-security-agent/lib/core/lambda-delegated-task-service.js +90 -0
  66. package/lib/nr-security-agent/lib/core/logging.js +176 -0
  67. package/lib/nr-security-agent/lib/core/sec-agent-constants.js +173 -0
  68. package/lib/nr-security-agent/lib/core/sec-util.js +166 -0
  69. package/lib/nr-security-agent/lib/core/sha-size-util.js +338 -0
  70. package/lib/nr-security-agent/lib/core/sha_worker.js +24 -0
  71. package/lib/nr-security-agent/lib/core/startup-config.js +29 -0
  72. package/lib/nr-security-agent/lib/core/statusUtils.js +157 -0
  73. package/lib/nr-security-agent/lib/core/timeunit.js +44 -0
  74. package/lib/nr-security-agent/lib/core/websocket-client.js +335 -0
  75. package/lib/nr-security-agent/lib/core/worker-entities.js +82 -0
  76. package/lib/nr-security-agent/lib/core/worker.js +148 -0
  77. package/lib/nr-security-agent/lib/core/xss-utils.js +297 -0
  78. package/lib/nr-security-agent/lib/models/lambda-delegated-task/constants.js +12 -0
  79. package/lib/nr-security-agent/lib/models/lambda-delegated-task/index.js +15 -0
  80. package/lib/nr-security-agent/lib/models/lambda-delegated-task/lambda-delegated-sha-calculation.js +37 -0
  81. package/lib/nr-security-agent/lib/models/lambda-delegated-task/lambda-delegated-task-base.js +50 -0
  82. package/lib/nr-security-agent/lib/models/lambda-delegated-task/lambda-delegated-task-type.js +17 -0
  83. package/lib/nr-security-agent/resources/cert.pem +31 -0
  84. package/lib/nr-security-agent/resources/config.js +19 -0
  85. package/lib/nr-security-agent/resources/default-policy.yaml +36 -0
  86. package/lib/nr-security-api/index.js +111 -0
  87. package/package.json +95 -0
@@ -0,0 +1,443 @@
1
+ /*
2
+ * Copyright 2023 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const WebSocket = require('ws');
9
+ const RingBuffer = require('ringbufferjs');
10
+ const stringify = require('fast-safe-stringify');
11
+ const { EventEmitter } = require('events');
12
+
13
+ const { Agent } = require('../../agent');
14
+ const logs = require('../../logging');
15
+ const hc = require('../../health-check');
16
+ const fs = require('fs');
17
+ const path = require('path');
18
+ const { promisify } = require('../../sec-util');
19
+ const ResponseHandler = require('./response');
20
+ const { EMPTY_APPLICATION_UUID, LOG_MESSAGES } = require('../../sec-agent-constants');
21
+ const statusUtils = require('../../statusUtils');
22
+ const commonUtils = require('../../commonUtils');
23
+
24
+ const BUSY = 'busy';
25
+ const IDLE = 'idle';
26
+ const CONNECTING = 'connecting';
27
+ const WS_ON_OPEN = 'open';
28
+ const WS_ON_MSG = 'message';
29
+ const WS_ON_ERR = 'error';
30
+ const ACK = 'ACK';
31
+ const INIT_PING_RETRY_DELAY_ON_FAIL = 200; // in ms
32
+ const RECONNECTION_DELAY = 500; // ms
33
+ const APPLICATION_INFO_JSON_NAME = 'applicationinfo';
34
+ let APP_INFO;
35
+
36
+ const queue = new RingBuffer(1000);
37
+ let logger = logs.getLogger();
38
+ const initLogger = logs.getInitLogger();
39
+ let webSocket;
40
+ let pingIntervalConst;
41
+ let initTimeOut;
42
+
43
+ /**
44
+ * defines the WebSocket callbacks object
45
+ *
46
+ * @param {Function} onOpen
47
+ * @param {Function} onMessage
48
+ * @param {Function} onError
49
+ */
50
+ function WSCallbacks(onOpen, onMessage, onError) {
51
+ this.onOpen = onOpen;
52
+ this.onMessage = onMessage;
53
+ this.onError = onError;
54
+ }
55
+
56
+
57
+
58
+
59
+ /**
60
+ * This defines the websocket and related
61
+ * methods
62
+ *
63
+ * @param {String} uri - to connect to
64
+ * @param {WSCallbacks} callbacks - on open, on message and on error callbacks
65
+ */
66
+ function SecWebSocket(uri, callbacks = {}, logr = null) {
67
+ this.instance = undefined;
68
+ this.isICReadyForEvents = false;
69
+ this.uri = uri;
70
+ this.event = new EventEmitter();
71
+ this.openCB = (callbacks.onOpen || defaultOnOpenCB()).bind(this);
72
+ this.msgCB = (callbacks.onMessage || defaultOnMsgCB()).bind(this);
73
+ this.errCB = (callbacks.onError || defaultOnErrCB()).bind(this);
74
+ logger = logr || logger;
75
+ this.wsRetryCount = 0;
76
+ this.init();
77
+ }
78
+
79
+ SecWebSocket.prototype = {};
80
+ SecWebSocket.prototype.constructor = SecWebSocket;
81
+
82
+
83
+ /**
84
+ * Initiates a new web socket connection.
85
+ */
86
+ SecWebSocket.prototype.init = function init() {
87
+ if (webSocket) {
88
+ try {
89
+ webSocket.removeAllListeners('open');
90
+ webSocket.removeAllListeners('close');
91
+ webSocket.removeAllListeners('message');
92
+ webSocket.terminate();
93
+ } catch (error) {
94
+ logger.debug("Error while terminating webSocket instance", error);
95
+ }
96
+ }
97
+ setWebSocketConn();
98
+ this.setValidatorNotReadyForEvents();
99
+ const validatorService = commonUtils.getValidatorServiceEndpointURL();
100
+ const authHeaders = require('../../Auth-headers').getInstance();
101
+ initLogger.info(`[STEP-4][BEGIN][WS] Connecting to Prevent-Web service at ${validatorService}`);
102
+ let cert = ''
103
+ try {
104
+ const certPath = commonUtils.getPathOfCACert();
105
+ cert = fs.readFileSync(certPath, 'utf8');
106
+ } catch (error) {
107
+ logger.error("Error in reading certificate:", error);
108
+ }
109
+
110
+ webSocket = new WebSocket(validatorService, null, { headers: authHeaders, cert: cert });
111
+
112
+ webSocket.on(WS_ON_OPEN, this.openCB);
113
+ webSocket.on(WS_ON_MSG, this.msgCB);
114
+ webSocket.on(WS_ON_ERR, this.errCB);
115
+ this.instance = webSocket;
116
+ };
117
+
118
+ /**
119
+ * Re-initiates the websocket by disconnecting
120
+ * and initiating a new websoc connection.
121
+ */
122
+ SecWebSocket.prototype.reconnect = function reconnect() {
123
+ const { instance } = this;
124
+
125
+ if (instance.readyState === WebSocket.CONNECTING &&
126
+ process.env.CSEC_WS_STATE === CONNECTING) {
127
+ return;
128
+ }
129
+ setWebSocketConn();
130
+ this.setValidatorNotReadyForEvents();
131
+
132
+ if (instance.readyState === WebSocket.OPEN) {
133
+ this.openCB();
134
+ return;
135
+ }
136
+ process.env.WS_HEALTH = 'Error';
137
+ logger.debug(LOG_MESSAGES.DETECTED_BROKEN_CONN);
138
+ this.obeyReconnect();
139
+
140
+ };
141
+
142
+ SecWebSocket.prototype.obeyReconnect = function obeyReconnect() {
143
+ const { instance } = this;
144
+ if(initTimeOut){
145
+ clearTimeout(initTimeOut);
146
+ }
147
+
148
+ initTimeOut = setTimeout(() => {
149
+ logger.debug("Terminating ws instance and reconnecting");
150
+ try {
151
+ instance.terminate();
152
+ } catch (err) {
153
+ logger.debug("Error while terminating ws instance");
154
+ }
155
+ this.init();
156
+ }, 15000)
157
+
158
+ }
159
+
160
+ SecWebSocket.prototype.pingWS = async function pingWS() {
161
+ const self = this;
162
+ try {
163
+ await promisify(self.instance, self.instance.ping)(ACK, true, function (err) {
164
+ if (err) {
165
+ logger.debug("Error while pinging:", err);
166
+ self.obeyReconnect();
167
+ }
168
+ });
169
+ } catch (err) {
170
+ logger.debug("error in ping:", err);
171
+ statusUtils.addErrortoBuffer(err);
172
+ return;
173
+ }
174
+ }
175
+
176
+ /**
177
+ * sends the event over the websocket instance.
178
+ * @param {JSON} event
179
+ */
180
+ SecWebSocket.prototype.dispatch = async function dispatch(event) {
181
+ if (event.jsonName === APPLICATION_INFO_JSON_NAME) {
182
+ APP_INFO = event;
183
+ }
184
+ RegExp.prototype.toJSON = RegExp.prototype.toString;
185
+ const eventStr = stringify(event);
186
+ if (!this.instance ||
187
+ this.instance.readyState !== WebSocket.OPEN ||
188
+ !this.isICReadyForEvents
189
+ ) {
190
+ handleDispatchFailure(this, event, eventStr);
191
+ return;
192
+ }
193
+ try {
194
+ aquireWebSocket();
195
+ logger.debug(LOG_MESSAGES.EVENT_SENT + eventStr);
196
+ await promisify(this.instance, this.instance.send)(eventStr, { mask: true });
197
+ releaseWebSocket();
198
+ } catch (error) {
199
+ logger.debug(LOG_MESSAGES.ERROR_WHILE_SEND_EVENT, eventStr, error);
200
+ statusUtils.addErrortoBuffer(error);
201
+ handleDispatchFailure(this, event, eventStr);
202
+ }
203
+ };
204
+
205
+ /**
206
+ * sends the applicationInfor over the websocket instance.
207
+ * @param {JSON} applicationInfoJSON
208
+ */
209
+ SecWebSocket.prototype.dispatchApplicationInfo = async function dispatchApplicationInfo(applicationInfoJSON) {
210
+ const eventStr = stringify(applicationInfoJSON);
211
+ if (applicationInfoJSON.applicationUUID === EMPTY_APPLICATION_UUID) {
212
+ throw new Error('ApplicationInfo not completely Initialized, No application identification detail found!');
213
+ }
214
+ if (this.instance.readyState !== WebSocket.OPEN) {
215
+ logger.warn('Tried to send ApplicationInfo when socket was not open');
216
+ }
217
+ try {
218
+ await promisify(this.instance, this.instance.send)(eventStr, { mask: true });
219
+ } catch (error) {
220
+ statusUtils.addErrortoBuffer(error);
221
+ logger.warn('Error while sending applicationInfo:', error);
222
+ this.obeyReconnect();
223
+ }
224
+ };
225
+
226
+
227
+
228
+ /**
229
+ * this sets the isICReadyForEvents property
230
+ */
231
+ SecWebSocket.prototype.setICReadyForEvents = function setICReadyForEvents() {
232
+ this.isICReadyForEvents = true;
233
+ };
234
+
235
+ /**
236
+ * this unsets the isICReadyForEvents property
237
+ */
238
+ SecWebSocket.prototype.setValidatorNotReadyForEvents = function setValidatorNotReadyForEvents() {
239
+ this.isICReadyForEvents = false;
240
+ };
241
+
242
+ /**
243
+ * This would flush all the events out of
244
+ * event queue and publish to IC.
245
+ *
246
+ * If the send fails there is no way to
247
+ * recover these events.
248
+ */
249
+ SecWebSocket.prototype.flushEventQueue = async function flushEventQueue() {
250
+ aquireWebSocket();
251
+ try {
252
+ const sentEvents = [];
253
+ for (let counter = 0; counter < queue.size(); counter += 1) {
254
+ hc.getInstance().registerEventProcessed();
255
+ sentEvents.push(promisify(this.instance, this.instance.send)(queue.deq(), { mask: true }));
256
+ }
257
+ const results = await Promise.all(sentEvents);
258
+ hc.getInstance().registerEventsSent(results.length);
259
+ } catch (err) {
260
+ statusUtils.addErrortoBuffer(err);
261
+ logger.error('Flush failed, reception of all events on IC couldn\'t be ensured.');
262
+ } finally {
263
+ releaseWebSocket();
264
+ }
265
+ };
266
+
267
+ /**
268
+ * this handles the event dispatch failure
269
+ *
270
+ * @param {SecWebSocket} self
271
+ * @param {String} eventStr
272
+ */
273
+ const handleDispatchFailure = (self, event, eventStr) => {
274
+ // we would want to drop applicationinfo events as the latest
275
+ // applicationinfo would anyway be relayed on reconnection
276
+ // so feeding an old applicationinfo JSON would be incorrect
277
+ if (eventStr && event.jsonName !== APPLICATION_INFO_JSON_NAME) {
278
+ hc.getInstance().registerEventDrop();
279
+ queue.enq(eventStr);
280
+ }
281
+ process.env.WS_HEALTH = 'Error';
282
+ // If the reconnection is not already in progress
283
+ // we would want to reconnect to IC
284
+ // self.reconnect();
285
+ };
286
+
287
+ /**
288
+ * This is the websocket on open default listener
289
+ * generator.
290
+ *
291
+ * If we fail to ping the ws server, we
292
+ * will retry sending the init ping after a
293
+ * defined delay.
294
+ * Otherwise if the ping is successful we will
295
+ * dispatch the application info.
296
+ *
297
+ * @param {SecWebSocket} self
298
+ */
299
+ const defaultOnOpenCB = () => async function onOpen() {
300
+ const self = this;
301
+ if (self.isICReadyForEvents) {
302
+ return;
303
+ }
304
+ if (self.instance.readyState !== WebSocket.OPEN) {
305
+ self.reconnect();
306
+ return;
307
+ }
308
+ if (pingIntervalConst) {
309
+ clearInterval(pingIntervalConst);
310
+ }
311
+ pingIntervalConst = setInterval(() => {
312
+ self.pingWS();
313
+ }, 30000)
314
+
315
+ try {
316
+ initLogger.info(LOG_MESSAGES.WS_CONNECTED);
317
+
318
+ this.wsRetryCount = 0;
319
+ process.env.WS_HEALTH = 'OK';
320
+
321
+ const applicationInfo = APP_INFO || Agent.getAgent().applicationInfo;
322
+ initLogger.info(LOG_MESSAGES.SENDING_APPINFO, JSON.stringify(applicationInfo));
323
+ await self.dispatchApplicationInfo(applicationInfo);
324
+
325
+ // by now we expect IC to be ready
326
+ aquireWebSocket(true);
327
+ self.setICReadyForEvents();
328
+ // we would also want the event queue to be flushed
329
+ await self.flushEventQueue();
330
+ ResponseHandler.FuzzRequestHandler.setLastFuzzEnventTime();
331
+ releaseWebSocket();
332
+ initLogger.info(LOG_MESSAGES.SENDING_APPINFO_COMPLETE, JSON.stringify(applicationInfo));
333
+ } catch (err) {
334
+ logger.error(`Connection broken: ${err.message}`);
335
+ statusUtils.addErrortoBuffer(err);
336
+ process.env.WS_HEALTH = 'Error';
337
+ setWebSocketConn();
338
+ self.setValidatorNotReadyForEvents();
339
+ setTimeout(self.openCB, INIT_PING_RETRY_DELAY_ON_FAIL);
340
+ }
341
+ };
342
+
343
+ /**
344
+ * This is the websocket on error default listener
345
+ * generator.
346
+ *
347
+ * This will close and re-establish the websocket
348
+ * connection once if invoked.
349
+ *
350
+ * @param {SecWebSocket} self
351
+ */
352
+ const defaultOnMsgCB = () => function onMessage(data) {
353
+ const json = JSON.parse(data);
354
+ ResponseHandler.handle(json);
355
+ };
356
+
357
+ /**
358
+ * This is the websocket on error default listener
359
+ * generator.
360
+ *
361
+ * This will close and re-establish the websocket
362
+ * connection once if invoked.
363
+ *
364
+ * @param {SecWebSocket} self
365
+ */
366
+ const defaultOnErrCB = (error) => function onClose(error) {
367
+ const self = this;
368
+ if (error && error.code && (error.code === 'ECONNREFUSED' || error.code === 'EPIPE' || error.code === 'ECONNRESET')) {
369
+ logger.debug("WS Client Error callback called:", error);
370
+ self.obeyReconnect();
371
+ }
372
+ else {
373
+ aquireWebSocket(true);
374
+ self.reconnect();
375
+ }
376
+ statusUtils.addErrortoBuffer(new Error('Error connecting to websocket'));
377
+ process.env.WS_HEALTH = 'Error';
378
+ };
379
+
380
+ SecWebSocket.Events = {
381
+ BUSY,
382
+ IDLE,
383
+ CONNECTING
384
+ };
385
+
386
+ SecWebSocket.States = {
387
+ BUSY,
388
+ IDLE,
389
+ CONNECTING
390
+ };
391
+ SecWebSocket.PING_MSG = ACK;
392
+ SecWebSocket.PING_RETRY_INTERVAL = INIT_PING_RETRY_DELAY_ON_FAIL;
393
+ SecWebSocket.RECONNECTION_DELAY = RECONNECTION_DELAY;
394
+
395
+ /**
396
+ * Checks if the websocket is currently busy
397
+ * by checking on CSEC_WS_STATE
398
+ *
399
+ * @returns {boolean} busy
400
+ */
401
+ function isWebSocketBusy() {
402
+ return process.env.CSEC_WS_STATE !== IDLE;
403
+ }
404
+
405
+ /**
406
+ * Sets the websocket state as connecting
407
+ */
408
+ function setWebSocketConn() {
409
+ process.env.CSEC_WS_ACQUIRED_COUNT = 0;
410
+ process.env.CSEC_WS_STATE = CONNECTING;
411
+ }
412
+
413
+ /**
414
+ * marks the WS being aquired to be used in an operation
415
+ */
416
+ function aquireWebSocket(forced = false) {
417
+ if (!forced && process.env.CSEC_WS_STATE === CONNECTING) return;
418
+
419
+ let count = Number.parseInt(process.env.CSEC_WS_ACQUIRED_COUNT);
420
+ count += 1;
421
+ process.env.CSEC_WS_ACQUIRED_COUNT = count;
422
+ process.env.CSEC_WS_STATE = BUSY;
423
+ }
424
+
425
+ /**
426
+ * marks the WS being released after use in an operation
427
+ */
428
+ function releaseWebSocket() {
429
+ const { CSEC_WS_STATE, CSEC_WS_ACQUIRED_COUNT } = process.env;
430
+ let count = Number.parseInt(CSEC_WS_ACQUIRED_COUNT);
431
+ count = count > 0 ? count - 1 : 0;
432
+ process.env.CSEC_WS_ACQUIRED_COUNT = count;
433
+ process.env.CSEC_WS_STATE = count === 0 && CSEC_WS_STATE !== CONNECTING ? CSEC_WS_STATE : IDLE;
434
+ }
435
+
436
+ module.exports = {
437
+ WSCallbacks,
438
+ SecWebSocket,
439
+ isWebSocketBusy,
440
+ setWebSocketConn,
441
+ aquireWebSocket,
442
+ releaseWebSocket
443
+ };
@@ -0,0 +1,186 @@
1
+ /*
2
+ * Copyright 2023 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ 'use strict';
7
+ const { JSON_NAME, COLLECTOR_TYPE, LANGUAGE, EMPTY_STR, STRING, NR_CSEC_FUZZ_REQUEST_ID } = require('./sec-agent-constants');
8
+ const { AGENT_VERSION } = require('../../resources/config');
9
+ const policyManager = require('./Policy');
10
+ const LinkingMetaData = require('./LinkingMetadata');
11
+ const API = require('../../../nr-security-api');
12
+ const NRAgent = API.getNRAgent();
13
+ const lodash = require('lodash');
14
+ const commonUtils = require('./commonUtils');
15
+ /**
16
+ * BasicInfo Structure, which is applicatble to each
17
+ * Event generated from agent.
18
+ */
19
+ function BasicInfo() {
20
+ this.jsonName = undefined;
21
+ this.pid = undefined;
22
+ this.applicationUUID = undefined;
23
+ this.timestamp = Date.now();
24
+ this.jsonVersion = AGENT_VERSION;
25
+ this.collectorType = COLLECTOR_TYPE;
26
+ this.language = LANGUAGE;
27
+ this.framework = EMPTY_STR;
28
+ this.groupName = commonUtils.getCSECmode();
29
+ this.policyVersion = (!lodash.isEmpty(policyManager.getInstance().data)) ? policyManager.getInstance().data.version : 'DEFAULT';
30
+
31
+ if (NRAgent && NRAgent.config) {
32
+ this.entityGuid = NRAgent.config.entity_guid;
33
+ this.linkingMetadata = LinkingMetaData.getLinkingMetadata();
34
+ this.linkingMetadata.agentRunId = NRAgent.config.run_id;
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Creates a new Event Object from the passed info.
40
+ *
41
+ * @param {string} fileName
42
+ * @param {string} funcName
43
+ * @param {number} lineNumber
44
+ * @param {*} argument
45
+ * @param {number} eid
46
+ * @param {ApplicationInfo} applicationInfo
47
+ * @param {Object} httpRequest
48
+ * @param {string} jsonName
49
+ * @param {string} eventName
50
+ * @param {Object} source
51
+ *
52
+ * @returns {SecEvent} event
53
+ */
54
+
55
+ function SecEvent(fileName, funcName, lineNumber, argument, eid, applicationInfo, httpRequest, eventName, source, eventCategory, metaData, stkTrace, apiId, isAPIBlocked) {
56
+ BasicInfo.call(this);
57
+ const policy = policyManager.getInstance();
58
+ if (argument) {
59
+ argument = argument instanceof Array ? argument : [argument];
60
+ } else if (typeof argument === STRING) {
61
+ argument = [argument];
62
+ } else {
63
+ argument = null;
64
+ }
65
+ this.jsonVersion = applicationInfo.jsonVersion ? applicationInfo.jsonVersion : null;
66
+ this.collectorVersion = applicationInfo.collectorVersion ? applicationInfo.collectorVersion : null;
67
+ this.buildNumber = applicationInfo.buildNumber ? applicationInfo.buildNumber : null;
68
+ this.source = source || null;
69
+ this.applicationUUID = applicationInfo.applicationUUID ? applicationInfo.applicationUUID : null;
70
+ this.jsonName = JSON_NAME.EVENT;
71
+ this.userFileName = fileName || null;
72
+ this.userMethodName = funcName || null;
73
+ try {
74
+ lineNumber = parseInt(lineNumber);
75
+ } catch (error) {
76
+ }
77
+ this.lineNumber = lineNumber || -1;
78
+ this.parameters = argument;
79
+ this.eventGenerationTime = new Date().getTime();
80
+ this.eid = eid || null;
81
+ this.pid = applicationInfo.pid ? applicationInfo.pid : null;
82
+ this.httpRequest = httpRequest || null;
83
+ this.caseType = eventName || null;
84
+ this.eventCategory = eventCategory || null;
85
+ this.metaData = metaData || {
86
+ TRIGGER_VIA_RCI: false,
87
+ RCI_METHOD_CALLS: []
88
+ };
89
+ this.stacktrace = stkTrace;
90
+ this.apiId = apiId || null;
91
+ this.isAPIBlocked = isAPIBlocked || false;
92
+ const vulnerabilityScan = policy.data.vulnerabilityScan;
93
+ const dynamicScanning = vulnerabilityScan.enabled && vulnerabilityScan.iastScan.enabled;
94
+ this.isIASTEnable = dynamicScanning;
95
+ if (this.isIASTEnable) {
96
+ this.id = eid + Math.floor(Math.random() * (100000 - 1) + 1);
97
+ } else {
98
+ this.id = eid;
99
+ }
100
+ if (httpRequest && httpRequest.headers[NR_CSEC_FUZZ_REQUEST_ID]) {
101
+ this.isIASTRequest = true;
102
+ }
103
+ else {
104
+ this.isIASTRequest = false;
105
+ }
106
+ this.eventType = 'sec_event';
107
+ if (NRAgent) {
108
+ const nrTransaction = NRAgent.getTransaction();
109
+ if (nrTransaction) {
110
+ this.linkingMetadata.transactionId = nrTransaction.id;
111
+ const segment = NRAgent.tracer.getSegment();
112
+ if (segment) {
113
+ this.linkingMetadata['span.id'] = segment.getSpanId();
114
+ }
115
+ this.linkingMetadata.isSampled = nrTransaction.isSampled();
116
+ this.linkingMetadata['trace.id'] = nrTransaction.traceId;
117
+ }
118
+ }
119
+ }
120
+
121
+ SecEvent.prototype = Object.create(BasicInfo.prototype);
122
+ SecEvent.prototype.constructor = SecEvent;
123
+
124
+ module.exports = {
125
+ BasicInfo,
126
+ SecEvent: SecEvent,
127
+ EVENT_TYPE: {
128
+ SYSTEM_COMMAND: 'SYSTEM_COMMAND',
129
+ SYSTEM_EXIT: 'SYSTEM_EXIT',
130
+ FILE_OPERATION: 'FILE_OPERATION',
131
+ FILE_INTEGRITY: 'FILE_INTEGRITY',
132
+ DB_COMMAND: 'SQL_DB_COMMAND',
133
+ NOSQL_DB_COMMAND: 'NOSQL_DB_COMMAND',
134
+ HTTP_REQUEST: 'HTTP_REQUEST',
135
+ CODE_INJECTION: 'CODE_INJECTION',
136
+ XXE: 'XXE',
137
+ CIPHER: 'CIPHER',
138
+ HASH: 'HASH',
139
+ RANDOM: 'RANDOM',
140
+ UNVALIDATED_REDIRECT: 'UNVALIDATED_REDIRECT',
141
+ REFLECTED_XSS: 'REFLECTED_XSS',
142
+ XPATH: 'XPATH',
143
+ LDAP: 'LDAP'
144
+
145
+ },
146
+ EVENT_CATEGORY: {
147
+ MYSQL: 'MYSQL',
148
+ POSTGRES: 'POSTGRES',
149
+ ORACLE: 'ORACLE',
150
+ MONGO: 'MONGO',
151
+ MSSQL: 'MSSQL',
152
+ SQLITE: 'SQLITE',
153
+ FILE: 'FILE',
154
+ SYS: 'SYSTEM',
155
+ HTTP: 'HTTP',
156
+ CODE_INJECTION: 'CODE_INJECTION',
157
+ XXE: 'XXE',
158
+ CRYPTO: 'CRYPTO',
159
+ HASH: 'HASH',
160
+ WEAKRANDOM: 'WEAKRANDOM',
161
+ UNVALIDATED_REDIRECT: 'UNVALIDATED_REDIRECT',
162
+ REFLECTED_XSS: 'REFLECTED_XSS',
163
+ XPATH: 'XPATH',
164
+ LDAP: 'LDAP'
165
+ },
166
+
167
+ VUNERABILITIES:
168
+ {
169
+ SQLI: 'SQLI',
170
+ SXSS: 'SXSS',
171
+ RXSS: 'RXSS',
172
+ LDAP: 'LDAP',
173
+ RCE: 'RCE',
174
+ RCI: 'RCI',
175
+ FILE_ACCESS: 'FILE_ACCESS',
176
+ NOSQLI: 'NOSQLI',
177
+ WEAK_RANDOM: 'WEAK_RANDOM',
178
+ XPATH: 'XPATH',
179
+ SSRF: 'SSRF',
180
+ CRYPTO: 'CRYPTO',
181
+ HASH: 'HASH',
182
+ XXE: 'XXE',
183
+ UNVALIDATED_REDIRECT: 'UNVALIDATED_REDIRECT'
184
+ }
185
+
186
+ };