@newrelic/security-agent 0.1.3 → 0.2.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 (24) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/THIRD_PARTY_NOTICES.md +3 -3
  3. package/lib/instrumentation-security/core/constants.js +0 -1
  4. package/lib/instrumentation-security/hooks/fs/nr-fs.js +6 -5
  5. package/lib/instrumentation-security/hooks/mysql/nr-mysql.js +16 -0
  6. package/lib/instrumentation-security/hooks/require/nr-require.js +12 -5
  7. package/lib/nr-security-agent/lib/core/Auth-headers.js +1 -0
  8. package/lib/nr-security-agent/lib/core/applicationinfo.js +1 -1
  9. package/lib/nr-security-agent/lib/core/commonUtils.js +10 -10
  10. package/lib/nr-security-agent/lib/core/connections/websocket/index.js +0 -6
  11. package/lib/nr-security-agent/lib/core/connections/websocket/response/IASTUtils.js +50 -0
  12. package/lib/nr-security-agent/lib/core/connections/websocket/response/collector-policy-handler.js +4 -1
  13. package/lib/nr-security-agent/lib/core/connections/websocket/response/fuzz-request-handler.js +90 -31
  14. package/lib/nr-security-agent/lib/core/connections/websocket/response/iast-cool-down.js +15 -0
  15. package/lib/nr-security-agent/lib/core/connections/websocket/response/iast-record-deletion.js +19 -0
  16. package/lib/nr-security-agent/lib/core/connections/websocket/response/index.js +17 -5
  17. package/lib/nr-security-agent/lib/core/connections/websocket/websocket.js +9 -58
  18. package/lib/nr-security-agent/lib/core/logging.js +89 -71
  19. package/lib/nr-security-agent/lib/core/sec-agent-constants.js +3 -2
  20. package/lib/nr-security-agent/lib/core/statusUtils.js +1 -1
  21. package/lib/nr-security-agent/lib/core/websocket-client.js +5 -168
  22. package/package.json +4 -4
  23. package/lib/nr-security-agent/lib/core/worker-entities.js +0 -82
  24. package/lib/nr-security-agent/lib/core/worker.js +0 -148
package/CHANGELOG.md CHANGED
@@ -1,3 +1,19 @@
1
+ ### v0.2.1 (2023-08-07)
2
+ #### Bug Fixes
3
+ * Pinned check-disk-space to v3.3.1 to support Node.js v14
4
+ #### Miscellaneous Chores
5
+ * deps: Updated semver to v7.5.4 and @aws-sdk/client-lambda to v3.363.0
6
+ #### Continuous Integration
7
+ * Add Node.js 20.x to CI
8
+
9
+ ### v0.2.0 (2023-07-24)
10
+ #### Features
11
+ * IAST data pull implementation
12
+ * Logging update
13
+
14
+ #### Bug Fixes
15
+ * Param fixes for mysql and file hooks.
16
+
1
17
  ### v0.1.3
2
18
  * Updated semver to v7.5.3 (Fix for CWE-1333)
3
19
  * Updated request-ip, log4js, html-entities, uuid and fast-safe-stringify to latest version.
@@ -75,7 +75,7 @@ code, the source code can be found at [https://github.com/newrelic/csec-node-age
75
75
 
76
76
  ### @aws-sdk/client-lambda
77
77
 
78
- This product includes source derived from [@aws-sdk/client-lambda](https://github.com/aws/aws-sdk-js-v3) ([v3.358.0](https://github.com/aws/aws-sdk-js-v3/tree/v3.358.0)), distributed under the [Apache-2.0 License](https://github.com/aws/aws-sdk-js-v3/blob/v3.358.0/LICENSE):
78
+ This product includes source derived from [@aws-sdk/client-lambda](https://github.com/aws/aws-sdk-js-v3) ([v3.379.1](https://github.com/aws/aws-sdk-js-v3/tree/v3.379.1)), distributed under the [Apache-2.0 License](https://github.com/aws/aws-sdk-js-v3/blob/v3.379.1/LICENSE):
79
79
 
80
80
  ```
81
81
  Apache License
@@ -311,7 +311,7 @@ THE SOFTWARE.
311
311
 
312
312
  ### check-disk-space
313
313
 
314
- This product includes source derived from [check-disk-space](https://github.com/Alex-D/check-disk-space) ([v3.4.0](https://github.com/Alex-D/check-disk-space/tree/v3.4.0)), distributed under the [MIT License](https://github.com/Alex-D/check-disk-space/blob/v3.4.0/LICENSE):
314
+ This product includes source derived from [check-disk-space](https://github.com/Alex-D/check-disk-space) ([v3.3.1](https://github.com/Alex-D/check-disk-space/tree/v3.3.1)), distributed under the [MIT License](https://github.com/Alex-D/check-disk-space/blob/v3.3.1/LICENSE):
315
315
 
316
316
  ```
317
317
  MIT License
@@ -684,7 +684,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
684
684
 
685
685
  ### semver
686
686
 
687
- This product includes source derived from [semver](https://github.com/npm/node-semver) ([v7.5.3](https://github.com/npm/node-semver/tree/v7.5.3)), distributed under the [ISC License](https://github.com/npm/node-semver/blob/v7.5.3/LICENSE):
687
+ This product includes source derived from [semver](https://github.com/npm/node-semver) ([v7.5.4](https://github.com/npm/node-semver/tree/v7.5.4)), distributed under the [ISC License](https://github.com/npm/node-semver/blob/v7.5.4/LICENSE):
688
688
 
689
689
  ```
690
690
  The ISC License
@@ -60,7 +60,6 @@ module.exports = {
60
60
  SLASHDOTDOT: '/..',
61
61
  UNDEFINED: 'undefined',
62
62
  SELF_FD_PATH: '/proc/self/fd/',
63
- CSEC_LAST_FUZZ_REQUEST_TIME: 'CSEC_LAST_FUZZ_REQUEST_TIME',
64
63
  NR_CSEC_FUZZ_REQUEST_ID: 'nr-csec-fuzz-request-id',
65
64
 
66
65
  };
@@ -16,6 +16,7 @@ const logger = API.getLogger();
16
16
  const { STRING, QUESTIONMARK, DOTDOTSLASH, UNDEFINED, SELF_FD_PATH, SLASH, SLASHDOTDOT, NR_CSEC_FUZZ_REQUEST_ID } = require('../../core/constants');
17
17
  const fsConsts = process.binding('constants').fs;
18
18
  const agentModule = API.getSecAgent();
19
+ const lodash = require('lodash');
19
20
 
20
21
  const requireHook = require('../require/nr-require');
21
22
 
@@ -127,7 +128,7 @@ function openHook(shim, mod, moduleName) {
127
128
  parameters[0] = arguments[0];
128
129
  }
129
130
  }
130
- if (request && typeof parameters[0] === STRING) {
131
+ if (request && typeof parameters[0] === STRING && !lodash.isEmpty(parameters[0]) ) {
131
132
  const policy = API.getPolicy();
132
133
  const dynamicScanningFlag = policy.data ? policy.data.vulnerabilityScan.iastScan.enabled : false;
133
134
  const url = request.url;
@@ -180,7 +181,7 @@ function probableToFAHooks(shim, mod, moduleName) {
180
181
  const interceptedArgs = [arguments[0]];
181
182
  shim.interceptedArgs = interceptedArgs;
182
183
  const request = requestManager.getRequest(shim);
183
- if (request && typeof arguments[0] === STRING) {
184
+ if (request && typeof arguments[0] === STRING && !lodash.isEmpty(arguments[0])) {
184
185
  const traceObject = secUtils.getTraceObject(shim);
185
186
  const secMetadata = securityMetaData.getSecurityMetaData(request, interceptedArgs, traceObject, secUtils.getExecutionId(), EVENT_TYPE.FILE_OPERATION, EVENT_CATEGORY.FILE)
186
187
  this.secEvent = API.generateSecEvent(secMetadata);
@@ -209,7 +210,7 @@ function probableToFIHooks(shim, mod, moduleName) {
209
210
  const interceptedArgs = [arguments[0]];
210
211
  shim.interceptedArgs = interceptedArgs;
211
212
  const request = requestManager.getRequest(shim);
212
- if (request && typeof arguments[0] === STRING) {
213
+ if (request && typeof arguments[0] === STRING && !lodash.isEmpty(arguments[0])) {
213
214
  const traceObject = secUtils.getTraceObject(shim);
214
215
  if (fun === COPY_FILE || fun === RENAME) {
215
216
  const secMetadata = securityMetaData.getSecurityMetaData(request, arguments[1], traceObject, secUtils.getExecutionId(), getCase(arguments[1]), EVENT_CATEGORY.FILE)
@@ -243,7 +244,7 @@ function probablePromiseToFAHooks(shim, mod, moduleName) {
243
244
  const interceptedArgs = [arguments[0]];
244
245
  shim.interceptedArgs = interceptedArgs;
245
246
  const request = requestManager.getRequest(shim);
246
- if (request && typeof arguments[0] === STRING) {
247
+ if (request && typeof arguments[0] === STRING && !lodash.isEmpty(arguments[0])) {
247
248
  const traceObject = secUtils.getTraceObject(shim);
248
249
  const secMetadata = securityMetaData.getSecurityMetaData(request, interceptedArgs, traceObject, secUtils.getExecutionId(), EVENT_TYPE.FILE_OPERATION, EVENT_CATEGORY.FILE)
249
250
  this.secEvent = API.generateSecEvent(secMetadata);
@@ -268,7 +269,7 @@ function probablePromiseToFIHooks(shim, mod, moduleName) {
268
269
  const interceptedArgs = [arguments[0]];
269
270
  shim.interceptedArgs = interceptedArgs;
270
271
  const request = requestManager.getRequest(shim);
271
- if (request && typeof arguments[0] === STRING) {
272
+ if (request && typeof arguments[0] === STRING && !lodash.isEmpty(arguments[0])) {
272
273
  const traceObject = secUtils.getTraceObject(shim);
273
274
  if (fun === COPY_FILE || fun === RENAME) {
274
275
  const secMetadata = securityMetaData.getSecurityMetaData(request, arguments[1], traceObject, secUtils.getExecutionId(), getCase(arguments[1]), EVENT_CATEGORY.FILE)
@@ -171,6 +171,19 @@ function wrapQueryable(shim, queryable, isPoolQuery) {
171
171
  }
172
172
  return true;
173
173
  }
174
+ /**
175
+ * Utility to check list contains only string
176
+ * @param {*} list
177
+ * @returns
178
+ */
179
+ function containsOnlyStrings(list) {
180
+ for (let i = 0; i < list.length; i++) {
181
+ if (typeof list[i] !== 'string') {
182
+ return false;
183
+ }
184
+ }
185
+ return true;
186
+ }
174
187
 
175
188
  /**
176
189
  * Utility to extract query from the intercepted args
@@ -199,6 +212,9 @@ function extractQueryArgs(shim, args) {
199
212
  param = args[1];
200
213
  param = Object.values(param)
201
214
  }
215
+ if(!containsOnlyStrings(param)){
216
+ param = [];
217
+ }
202
218
  return {
203
219
  rawQuery: rawQuery,
204
220
  param: param,
@@ -14,9 +14,11 @@ const Module = require('module');
14
14
  const refDirRegEx = /^(\.\/)|^(\.\.\/)/g;
15
15
  const path = require('path');
16
16
  const CSEC = 'nr-security-agent';
17
+ const FN_INSPECT = '@contrast/fn-inspect';
18
+ const NEWRELIC = 'newrelic';
17
19
 
18
20
  /**
19
- * Entry point for xpath module hook
21
+ * Entry point for require module hook
20
22
  * @param {*} shim
21
23
  * @param {*} mod
22
24
  * @param {*} moduleName
@@ -33,17 +35,22 @@ function initialize(shim) {
33
35
  if (arguments[0].match(refDirRegEx) && arguments[1] && arguments[1].path) {
34
36
  moduleName = path.resolve(arguments[1].path, arguments[0]);
35
37
  }
36
-
38
+
37
39
  let flag = false;
38
- if (moduleName && typeof (moduleName) === STRING && !moduleName.includes(CSEC)) {
40
+ if (moduleName && typeof (moduleName) === STRING && !moduleName.includes(CSEC) && !moduleName.includes(FN_INSPECT)) {
39
41
  flag = true;
40
42
  }
41
- else if (parent && parent.id && typeof (parent.id) === STRING && moduleName.includes(CSEC) && parent.id.includes(CSEC)) {
43
+ else if (parent && parent.id && typeof (parent.id) === STRING && moduleName.includes(CSEC) && parent.id.includes(CSEC) && moduleName.includes(FN_INSPECT)) {
42
44
  flag = false;
43
45
  }
44
- else if (parent && parent.id && moduleName && typeof (moduleName) === STRING && moduleName.includes(CSEC) && parent.id.includes(CSEC)) {
46
+ else if (parent && parent.id && moduleName && typeof (moduleName) === STRING && moduleName.includes(CSEC) && parent.id.includes(CSEC) && moduleName.includes(FN_INSPECT)) {
45
47
  flag = false;
46
48
  }
49
+
50
+ if ((parent && parent.id && typeof (parent.id) === STRING && parent.id.includes(NEWRELIC)) || moduleName.includes(NEWRELIC)){
51
+ flag = false;
52
+ }
53
+
47
54
  if (flag) {
48
55
  requireHook(shim, moduleName, parent);
49
56
  }
@@ -31,6 +31,7 @@ function AuthHeaders() {
31
31
  authHeaders['NR-CSEC-BUILD-NUMBER'] = appInfo.buildNumber;
32
32
  authHeaders['NR-ACCOUNT-ID'] = NRAgent.config.account_id;
33
33
  authHeaders['NR-LICENSE-KEY'] = NRAgent ? NRAgent.config.license_key : '';
34
+ authHeaders["NR-CSEC-IAST-DATA-TRANSFER-MODE"] = "PULL";
34
35
  } catch (error) {
35
36
  logger.error("Exception in preparing auth headers:", error);
36
37
  }
@@ -200,7 +200,7 @@ ApplicationInfo.prototype.updateSHAAndSize = async function updateSHAAndSize (Gl
200
200
  applicationInfo.sha256 = await shaSizeUtil.getSHA256ForFile(process.argv[0]);
201
201
 
202
202
  let stat = {};
203
- if (process.hasWorker) {
203
+ if (commonUtils.hasWorker()) {
204
204
  stat = await getApplicationSHAAndSizeFromWorker(applicationInfo, application.deployedPath);
205
205
  } else {
206
206
  stat = await shaSizeUtil.getApplicationSHAAndSize(application.deployedPath, GlobalPromise);
@@ -55,8 +55,14 @@ function getKindIdPair (identifier, hostId) {
55
55
  * @returns
56
56
  */
57
57
  function hasWorker () {
58
- process.hasWorker = false;
59
- return process.hasWorker;
58
+ let workerFlag = false;
59
+ try {
60
+ require('worker_threads');
61
+ workerFlag = true;
62
+ } catch (error) {
63
+ workerFlag = false;
64
+ }
65
+ return workerFlag;
60
66
  }
61
67
 
62
68
  function runtimeSupportsFunctionGenerators () {
@@ -136,13 +142,6 @@ function createDirectories () {
136
142
  */
137
143
  async function initialSetup () {
138
144
  try {
139
- checkDiskSpace(`${CSEC_HOME}`).then((diskSpace) => {
140
- if (diskSpace.free < 1000000000) {
141
- logger.error(LOG_MESSAGES.AVAIL_DISK_ERROR, `${CSEC_HOME}`, prettyBytes(diskSpace.free));
142
- process.exit();
143
- }
144
- }).catch(() => {
145
- });
146
145
  createDirectories();
147
146
  } catch (err) {
148
147
  logger.error(err);
@@ -329,7 +328,8 @@ function logRollOver () {
329
328
  return;
330
329
  }
331
330
  } catch (error) {
332
- logger.error('Error in getting stats of log file:', error);
331
+ logger.debug('Error in getting stats of log file:', error.message);
332
+ return;
333
333
  }
334
334
 
335
335
  try {
@@ -6,9 +6,6 @@
6
6
  const {
7
7
  SecWebSocket,
8
8
  WSCallbacks,
9
- aquireWebSocket,
10
- isWebSocketBusy,
11
- releaseWebSocket,
12
9
  setWebSocketConn
13
10
  } = require('./websocket');
14
11
 
@@ -17,9 +14,6 @@ const ResponseHandler = require('./response');
17
14
  module.exports = {
18
15
  SecWebSocket,
19
16
  WSCallbacks,
20
- aquireWebSocket,
21
- isWebSocketBusy,
22
- releaseWebSocket,
23
17
  setWebSocketConn,
24
18
  ResponseHandler
25
19
  };
@@ -0,0 +1,50 @@
1
+ /*
2
+ * Copyright 2023 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: New Relic Pre-Release
4
+ */
5
+ const { Agent } = require('../../../agent');
6
+ let completedRequestIds = new Set();
7
+ const PolicyManager = require('../../../Policy');
8
+ let batchSize;
9
+ const batchthreshold = 300;
10
+ function getCompletedRequestIds() {
11
+ return [...completedRequestIds];
12
+ }
13
+
14
+ function addRequestId(id) {
15
+ completedRequestIds.add(id);
16
+ }
17
+
18
+ function removeRequestId(id) {
19
+ completedRequestIds.delete(id);
20
+ }
21
+
22
+ function generateIASTDataRequest() {
23
+ const policyInstance = PolicyManager.getInstance();
24
+ if (policyInstance.data && policyInstance.data.vulnerabilityScan && policyInstance.data.vulnerabilityScan.iastScan) {
25
+ batchSize = batchSize ? batchSize : policyInstance.data.vulnerabilityScan.iastScan.probing.batchSize;
26
+ if (batchSize > batchthreshold) {
27
+ batchSize = policyInstance.data.vulnerabilityScan.iastScan.probing.batchSize;
28
+ }
29
+ }
30
+ if (getCompletedRequestIds().length >= batchSize || batchSize < batchthreshold) {
31
+ batchSize = (2 * batchSize);
32
+ }
33
+ let object = {};
34
+ object['jsonName'] = 'iast-data-request';
35
+ object['applicationUUID'] = Agent.getAgent().applicationInfo.applicationUUID;
36
+ object["batchSize"] = batchSize ? batchSize : 300;
37
+ object['completedRequestIds'] = getCompletedRequestIds();
38
+ return object;
39
+
40
+ }
41
+
42
+
43
+ module.exports = {
44
+ getCompletedRequestIds,
45
+ addRequestId,
46
+ removeRequestId,
47
+ generateIASTDataRequest,
48
+ }
49
+
50
+
@@ -11,7 +11,10 @@ module.exports.handler = function handler(json) {
11
11
  const policyData = json.data;
12
12
  const PolicyManager = require('../../../Policy');
13
13
  PolicyManager.setPolicyData(policyData);
14
-
14
+ if (policyData.vulnerabilityScan.enabled && policyData.vulnerabilityScan.iastScan.enabled) {
15
+ require('./fuzz-request-handler').startIASTSchedular();
16
+ }
17
+
15
18
  } catch (error) {
16
19
  logger.error('paring exception while parsing configuration', error);
17
20
  }
@@ -9,19 +9,19 @@ const stringify = require('fast-safe-stringify');
9
9
  const restClient = require('../../restclient');
10
10
  const { Agent } = require('../../../agent');
11
11
  const { FuzzFailEvent } = require('../../../FuzzFailEvent');
12
- const { hasWorker: isWorkerSupported } = require('../../../commonUtils');
13
12
  const { CSEC_HOME_TMP, COLON, NR_CSEC_FUZZ_REQUEST_ID, SLASH } = require('../../../sec-agent-constants');
14
13
  const LOCALHOST = 'localhost';
15
14
  const COLON_SLASH_SLASH = '://';
16
15
  const http = require('http');
17
16
  const https = require('https');
17
+ const IASTUtil = require('./IASTUtils');
18
+ const CSEC_SEP = ':IAST:';
19
+
18
20
  require('dns').setDefaultResultOrder('ipv4first')
19
21
 
20
22
  const {
21
23
  IS_LAMBDA_ENV,
22
- AWS_LAMBDA_FUNCTION_VERSION_ENV_IDENTIFIER,
23
- CSEC_LAST_FUZZ_REQUEST_TIME
24
- } = require('../../../sec-agent-constants');
24
+ AWS_LAMBDA_FUNCTION_VERSION_ENV_IDENTIFIER } = require('../../../sec-agent-constants');
25
25
  const statusUtils = require('../../../statusUtils');
26
26
 
27
27
  const find = `${SLASH}{{NR_CSEC_VALIDATOR_HOME_TMP}}`;
@@ -29,23 +29,71 @@ const CSEC_HOME_TMP_CONST = new RegExp(find, 'g');
29
29
 
30
30
  let logger;
31
31
  let lastFuzzEventTime = 0;
32
+ let iastIntervalConst;
33
+ let coolDownIntervalConst;
34
+ let additionalCoolDownTime = 0;
35
+ let fuzzedApiIDSet = new Set();
36
+
37
+
38
+ /**
39
+ * utility to start IAST Schedular
40
+ */
41
+ function startIASTSchedular() {
42
+ Agent.getAgent().client.dispatcher(IASTUtil.generateIASTDataRequest());
43
+ if (iastIntervalConst) {
44
+ clearInterval(iastIntervalConst);
45
+ }
46
+ iastIntervalConst = setInterval(() => {
47
+ let data = IASTUtil.generateIASTDataRequest();
48
+ let currentTime = Date.now();
49
+ let completedListSize = IASTUtil.getCompletedRequestIds().length;
50
+ let timeDiffInSeconds = ((currentTime - lastFuzzEventTime) / 1000);
51
+ logger.trace("Time difference since last fuzz request:", timeDiffInSeconds);
52
+ logger.trace("Completed requests so far:", completedListSize);
53
+
54
+ if (timeDiffInSeconds > 5 && additionalCoolDownTime == 0) {
55
+ Agent.getAgent().client.dispatcher(data);
56
+ }
57
+ }, 5000);
58
+ }
59
+
60
+ /**
61
+ * Utility to log scanned apiId
62
+ * @param {*} fuzzHeader
63
+ */
64
+ function logScannedApiId(fuzzHeader, requestURL) {
65
+ try {
66
+ let apiId = fuzzHeader.split(CSEC_SEP)[0]
67
+ if (apiId && !fuzzedApiIDSet.has(apiId) ) {
68
+ fuzzedApiIDSet.add(apiId);
69
+ logger.info("IAST Scan for API %s with ID : %s started.", requestURL, apiId);
70
+ }
71
+ } catch (error) {
72
+
73
+ }
74
+
75
+ }
32
76
 
33
77
  // handler function to parse fuzz event and prepare fuzz request
34
- function handler (json) {
35
- setLastFuzzEnventTime();
78
+ function handler(json) {
79
+ setLastFuzzEventTime();
36
80
  let rawFuzzRequest = json.arguments[0];
37
- logger.debug('Fuzz request received::' + rawFuzzRequest);
38
81
  rawFuzzRequest = rawFuzzRequest.replace(CSEC_HOME_TMP_CONST, CSEC_HOME_TMP);
39
82
  let fuzzRequest;
40
83
  try {
41
84
  fuzzRequest = JSON.parse(rawFuzzRequest);
85
+ fuzzRequest['id'] = json.id;
86
+ let completedList = IASTUtil.getCompletedRequestIds();
87
+ if (completedList.includes(json.id)) {
88
+ return;
89
+ }
42
90
  } catch (error) {
43
91
  logger.error('Parsing exeception in fuzz request: ', error);
44
92
  }
45
93
  if (!fuzzRequest) {
46
94
  return;
47
95
  }
48
-
96
+ logger.debug('Fuzz request received::' + JSON.stringify(json));
49
97
  logger.info('Fuzz request:: Method: ' + fuzzRequest.method);
50
98
  logger.info('Fuzz request:: Headers: ' + stringify(fuzzRequest.headers));
51
99
  logger.info('Fuzz request:: Data: ' + fuzzRequest.body);
@@ -61,7 +109,7 @@ function handler (json) {
61
109
  *
62
110
  * @param {Object} fuzzDetails
63
111
  */
64
- function handleFuzzRequest (fuzzDetails) {
112
+ function handleFuzzRequest(fuzzDetails) {
65
113
  const { fuzzRequest } = fuzzDetails;
66
114
  try {
67
115
  if (IS_LAMBDA_ENV) {
@@ -71,7 +119,7 @@ function handleFuzzRequest (fuzzDetails) {
71
119
  const ver = process.env[AWS_LAMBDA_FUNCTION_VERSION_ENV_IDENTIFIER];
72
120
  logger.info('Invoking Lambda:: ARN: ' + arn);
73
121
  logger.info('Invoking Lambda:: Version: ' + ver);
74
-
122
+
75
123
  } else {
76
124
  const config = parseAxiosHttpRequestToFuzz(fuzzRequest);
77
125
  const type = config.headers['content-type'];
@@ -81,10 +129,16 @@ function handleFuzzRequest (fuzzDetails) {
81
129
  config.headers['content-type'] = splitted[0];
82
130
  }
83
131
  }
132
+
133
+ if(fuzzRequest.headers && fuzzRequest.headers[NR_CSEC_FUZZ_REQUEST_ID]){
134
+ logScannedApiId(fuzzRequest.headers[NR_CSEC_FUZZ_REQUEST_ID], fuzzRequest.requestURI)
135
+ }
136
+
137
+
84
138
  logger.info('Firing http request:: URL: ' + config.url);
85
139
 
86
- const request = restClient.fireRequest(config);
87
- handleFuzzResponse(request, fuzzDetails);
140
+ const response = restClient.fireRequest(config);
141
+ handleFuzzResponse(response, fuzzDetails);
88
142
  }
89
143
  } catch (err) {
90
144
  statusUtils.addErrortoBuffer(err);
@@ -101,13 +155,14 @@ function handleFuzzRequest (fuzzDetails) {
101
155
  /**
102
156
  * Handles the fuzz response Promise.
103
157
  *
104
- * @param {Promise} request
158
+ * @param {Promise} response
105
159
  * @param {Object} fuzzDetails
106
160
  */
107
- function handleFuzzResponse (request, fuzzDetails) {
161
+ function handleFuzzResponse(response, fuzzDetails) {
108
162
  const { rawFuzzRequest, fuzzRequest } = fuzzDetails;
109
- if (request) {
110
- request.then(() => {
163
+ if (response) {
164
+ IASTUtil.addRequestId(fuzzRequest.id);
165
+ response.then(() => {
111
166
  logger.info('Fuzz success: ' + rawFuzzRequest);
112
167
  }).catch(() => {
113
168
  logger.debug('Error occured:', fuzzRequest.url, fuzzRequest);
@@ -121,11 +176,11 @@ function handleFuzzResponse (request, fuzzDetails) {
121
176
  *
122
177
  * @param {JSON} requestObject
123
178
  */
124
- function parseAxiosHttpRequestToFuzz (requestObject) {
179
+ function parseAxiosHttpRequestToFuzz(requestObject) {
125
180
  let serverName = requestObject.serverName ? requestObject.serverName : LOCALHOST;
126
181
  let host = serverName + COLON + requestObject.serverPort
127
182
  return {
128
- url: requestObject.protocol + COLON_SLASH_SLASH + host + requestObject.url,
183
+ url: requestObject.protocol + COLON_SLASH_SLASH + host + requestObject.url,
129
184
  method: requestObject.method,
130
185
  data: requestObject.body,
131
186
  headers: requestObject.headers,
@@ -141,7 +196,7 @@ function parseAxiosHttpRequestToFuzz (requestObject) {
141
196
  * set the handler logger
142
197
  * @param {*} l
143
198
  */
144
- function setLogger (l) {
199
+ function setLogger(l) {
145
200
  logger = l;
146
201
  };
147
202
 
@@ -149,25 +204,29 @@ function setLogger (l) {
149
204
  * Sets the last fuzz event time epoch
150
205
  * @param {Number} time
151
206
  */
152
- function setLastFuzzEnventTime (time = Date.now()) {
153
- if (isWorkerSupported()) {
154
- process.env[CSEC_LAST_FUZZ_REQUEST_TIME] = time;
155
- } else {
156
- lastFuzzEventTime = time;
157
- }
207
+ function setLastFuzzEventTime(time = Date.now()) {
208
+ lastFuzzEventTime = time;
158
209
  }
159
210
 
211
+
160
212
  /**
161
- * Returns last fuzz event time epoch
162
- * @returns {Number} lastFuzzEventTime
213
+ * Sets the last fuzz event time epoch
214
+ * @param {Number} time
163
215
  */
164
- function getLastFuzzEnventTime () {
165
- return isWorkerSupported() ? Number.parseInt(process.env[CSEC_LAST_FUZZ_REQUEST_TIME]) : lastFuzzEventTime;
216
+ function setAdditionalCoolDown(timeInSeconds) {
217
+ additionalCoolDownTime = timeInSeconds ? timeInSeconds : 10;
218
+ if (coolDownIntervalConst) {
219
+ clearTimeout(coolDownIntervalConst)
220
+ }
221
+ coolDownIntervalConst = setTimeout(() => {
222
+ additionalCoolDownTime = 0;
223
+ }, timeInSeconds * 1000);
166
224
  }
167
225
 
168
226
  module.exports = {
169
227
  handler,
170
228
  setLogger,
171
- setLastFuzzEnventTime,
172
- getLastFuzzEnventTime
229
+ setLastFuzzEventTime,
230
+ startIASTSchedular,
231
+ setAdditionalCoolDown
173
232
  };
@@ -0,0 +1,15 @@
1
+ /*
2
+ * Copyright 2023 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: New Relic Pre-Release
4
+ */
5
+
6
+ let logger;
7
+
8
+ module.exports.handler = function handler (json) {
9
+ logger.debug('IAST cool down command received:', JSON.stringify(json));
10
+ const fuzzRequestHandler = require('./fuzz-request-handler');
11
+ fuzzRequestHandler.setLastFuzzEventTime();
12
+ fuzzRequestHandler.setAdditionalCoolDown(json.data);
13
+ };
14
+
15
+ module.exports.setLogger = l => { logger = l };
@@ -0,0 +1,19 @@
1
+ /*
2
+ * Copyright 2023 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: New Relic Pre-Release
4
+ */
5
+
6
+ let logger;
7
+ const IASTUtil = require('./IASTUtils');
8
+ module.exports.handler = function handler (json) {
9
+ let deletionList = json.arguments;
10
+ let count = 0;
11
+ deletionList.forEach(element => {
12
+ count++;
13
+ IASTUtil.removeRequestId(element);
14
+ });
15
+ logger.debug("Purging confirmed %s IAST processed records: ", count, JSON.stringify(deletionList));
16
+
17
+ };
18
+
19
+ module.exports.setLogger = l => { logger = l };
@@ -13,6 +13,10 @@ const CollectorPolicyHandler = require('./collector-policy-handler');
13
13
  const CollectorPolicyErrorHandler = require('./collecotor-policy-error-handler');
14
14
  const NoOpHandler = require('./no-op-handler');
15
15
  const WSReconnect = require('./ws-reconnect');
16
+ const coolDown = require('./iast-cool-down');
17
+ const recordDeletion = require('./iast-record-deletion');
18
+ const logs = require('../../../logging');
19
+ let logger = logs.getLogger();
16
20
 
17
21
  const commandHandlerMap = {
18
22
  [SERVER_COMMAND.STARTUP_WELCOME_MSG]: StartupHandshakeHandler,
@@ -20,15 +24,23 @@ const commandHandlerMap = {
20
24
  [SERVER_COMMAND.FUZZ_REQUEST]: FuzzRequestHandler,
21
25
  [SERVER_COMMAND.COLLECTOR_CONFIG]: CollectorPolicyHandler,
22
26
  [SERVER_COMMAND.POLICY_ERROR]: CollectorPolicyErrorHandler,
23
- [SERVER_COMMAND.OBEY_WS_RECONNECT]: WSReconnect
27
+ [SERVER_COMMAND.OBEY_WS_RECONNECT]: WSReconnect,
28
+ [SERVER_COMMAND.IAST_RECORD_DELETE_CONFIRMATION]:recordDeletion,
29
+ [SERVER_COMMAND.ENTER_IAST_COOLDOWN]:coolDown
24
30
  };
25
31
 
26
32
  const handle = function handle (json) {
27
- if (json && json.controlCommand && json.arguments && commandHandlerMap[json.controlCommand]) {
28
- commandHandlerMap[json.controlCommand].handler.call(this, json);
29
- } else {
30
- NoOpHandler.handler.call(this, json);
33
+ try {
34
+ if (json && json.controlCommand && json.arguments && commandHandlerMap[json.controlCommand]) {
35
+ logger.debug("Incoming Control Command:", JSON.stringify(json));
36
+ commandHandlerMap[json.controlCommand].handler.call(this, json);
37
+ } else {
38
+ NoOpHandler.handler.call(this, json);
39
+ }
40
+ } catch (error) {
41
+ logger.error("Error in handling Control Commnad",error);
31
42
  }
43
+
32
44
  };
33
45
 
34
46
  const setLogger = function setLogger (logger) {