@newrelic/security-agent 1.5.0 → 2.1.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/THIRD_PARTY_NOTICES.md +48 -1
  3. package/lib/instrumentation-security/core/constants.js +8 -1
  4. package/lib/instrumentation-security/core/event-constants.js +5 -3
  5. package/lib/instrumentation-security/core/request-manager.js +40 -8
  6. package/lib/instrumentation-security/core/sec-utils.js +6 -5
  7. package/lib/instrumentation-security/hooks/director/nr-director.js +6 -6
  8. package/lib/instrumentation-security/hooks/express/nr-express.js +11 -8
  9. package/lib/instrumentation-security/hooks/fastify/nr-fastify.js +6 -6
  10. package/lib/instrumentation-security/hooks/fs/nr-fs.js +11 -28
  11. package/lib/instrumentation-security/hooks/grpc-js/nr-grpc.js +4 -4
  12. package/lib/instrumentation-security/hooks/hapi/nr-hapi.js +7 -7
  13. package/lib/instrumentation-security/hooks/http/nr-http.js +137 -13
  14. package/lib/instrumentation-security/hooks/koa/@koa/nr-@koa-router.js +5 -5
  15. package/lib/instrumentation-security/hooks/ldap/nr-ldap.js +4 -0
  16. package/lib/instrumentation-security/hooks/mongodb/nr-mongodb.js +4 -0
  17. package/lib/instrumentation-security/hooks/mysql/nr-mysql.js +4 -0
  18. package/lib/instrumentation-security/hooks/native/nr-childProcess.js +4 -0
  19. package/lib/instrumentation-security/hooks/postgres/nr-postgres.js +4 -0
  20. package/lib/instrumentation-security/hooks/restify/nr-restify.js +7 -7
  21. package/lib/instrumentation-security/hooks/undici/nr-undici.js +4 -0
  22. package/lib/instrumentation-security/hooks/xpath/nr-xpath.js +4 -0
  23. package/lib/nr-security-agent/index.js +38 -5
  24. package/lib/nr-security-agent/lib/core/Auth-headers.js +20 -0
  25. package/lib/nr-security-agent/lib/core/ExceptionReporting.js +1 -0
  26. package/lib/nr-security-agent/lib/core/Policy.js +0 -12
  27. package/lib/nr-security-agent/lib/core/agent.js +5 -1
  28. package/lib/nr-security-agent/lib/core/applicationinfo.js +2 -2
  29. package/lib/nr-security-agent/lib/core/commonUtils.js +141 -45
  30. package/lib/nr-security-agent/lib/core/connections/websocket/proxy-util.js +61 -0
  31. package/lib/nr-security-agent/lib/core/connections/websocket/response/IASTUtils.js +34 -6
  32. package/lib/nr-security-agent/lib/core/connections/websocket/response/fuzz-request-handler.js +36 -6
  33. package/lib/nr-security-agent/lib/core/connections/websocket/response/startup-handshake-handler.js +5 -1
  34. package/lib/nr-security-agent/lib/core/connections/websocket/response/ws-reconnect.js +7 -4
  35. package/lib/nr-security-agent/lib/core/connections/websocket/websocket.js +32 -14
  36. package/lib/nr-security-agent/lib/core/event.js +2 -2
  37. package/lib/nr-security-agent/lib/core/health-check.js +8 -2
  38. package/lib/nr-security-agent/lib/core/sec-agent-constants.js +2 -3
  39. package/lib/nr-security-agent/lib/core/sec-util.js +40 -4
  40. package/lib/nr-security-agent/lib/core/websocket-client.js +35 -12
  41. package/lib/nr-security-api/index.js +47 -15
  42. package/package.json +10 -4
  43. package/lib/nr-security-agent/lib/core/statusUtils.js +0 -165
@@ -23,6 +23,23 @@ let websocketHealth;
23
23
 
24
24
  const ringBuffer = require('ringbufferjs');
25
25
  const bufferedLogEvents = new ringBuffer(10);
26
+ const { CronJob } = require('cron');
27
+ let scanStartTime = 0;
28
+ let trafficStartedTime = 0;
29
+ const cron = require('cron');
30
+
31
+ const skip_detection_category_map = {
32
+ insecure_settings: ['CRYPTO', 'HASH', 'RANDOM', 'SECURE_COOKIE', 'TRUSTBOUNDARY'],
33
+ invalid_file_access: ['FILE_OPERATION', 'FILE_INTEGRITY'],
34
+ sql_injection: ['SQL_DB_COMMAND'],
35
+ nosql_injection: ['NOSQL_DB_COMMAND'],
36
+ ldap_injection: ['LDAP'],
37
+ javascript_injection: ['JS_INJECTION'],
38
+ command_injection: ['SYSTEM_COMMAND'],
39
+ xpath_injection: ['XPATH'],
40
+ ssrf: ['HTTP_REQUEST'],
41
+ rxss: ['REFLECTED_XSS']
42
+ }
26
43
 
27
44
 
28
45
  /**
@@ -133,7 +150,6 @@ function getOS() {
133
150
  function createDirectories() {
134
151
  createPathIfNotExist(`${CSEC_HOME}${SLASH}nr-security-home`);
135
152
  createPathIfNotExist(`${CSEC_HOME}${SLASH}nr-security-home${SLASH}logs`);
136
- createPathIfNotExist(`${CSEC_HOME}${SLASH}nr-security-home${SLASH}logs${SLASH}snapshots`);
137
153
  createPathIfNotExist(`${CSEC_HOME}${SLASH}nr-security-home${SLASH}tmp`);
138
154
  createPathIfNotExist(`${CSEC_HOME}${SLASH}nr-security-home${SLASH}tmp${SLASH}language-agent`);
139
155
  createPathIfNotExist(`${CSEC_HOME}${SLASH}nr-security-home${SLASH}tmp${SLASH}language-agent${SLASH}${getUUID()}`);
@@ -159,14 +175,11 @@ async function initialSetup() {
159
175
  */
160
176
  function isLogAccessible(logFileName) {
161
177
  return new Promise((resolve) => {
162
- if (logFileName === njsAgentConstants.STATUS_LOG_FILE && require('./statusUtils').getBufferedHC().length === 0) {
163
- resolve('OK');
164
- }
165
178
  fs.access(logFileName, fs.constants.F_OK | fs.constants.W_OK, (err) => {
166
179
  if (err) {
167
180
  resolve('Error');
168
181
  }
169
- else if ((!logs.isLoggerOk || logger.level.levelStr == 'OFF') && logFileName != njsAgentConstants.STATUS_LOG_FILE) {
182
+ else if ((!logs.isLoggerOk || logger.level.levelStr == 'OFF')) {
170
183
  resolve('Error');
171
184
  }
172
185
  else {
@@ -256,42 +269,6 @@ function isAgentActiveState() {
256
269
  function iastRestClientStatus() {
257
270
  return 'OK';
258
271
  }
259
- /**
260
- * Utiltity to remove older snapshots
261
- */
262
- function removeOlderSnapshots() {
263
- try {
264
- const basePath = njsAgentConstants.LOG_DIR + 'snapshots' + SLASH;
265
- const directoryContent = fs.readdirSync(basePath);
266
- const files = directoryContent.filter((filename) => {
267
- return fs.statSync(`${basePath}${SLASH}${filename}`).isFile();
268
- });
269
- const sorted = files.sort((a, b) => {
270
- const firstStat = fs.statSync(`${basePath}${SLASH}${a}`);
271
- const secondStat = fs.statSync(`${basePath}${SLASH}${b}`);
272
- return new Date(secondStat.mtime).getTime() - new Date(firstStat.mtime).getTime();
273
- });
274
- for (let i = 99; i < sorted.length; i++) {
275
- const fileToDelete = basePath + sorted[i];
276
- try {
277
- fs.unlink(fileToDelete, (err) => {
278
- if (err) {
279
- logger.error(err);
280
- } else {
281
- logger.debug('Snapshot deleted:', fileToDelete);
282
- }
283
- });
284
- } catch (error) {
285
- logger.error(error);
286
- }
287
- }
288
- } catch (error) {
289
- logger.debug(error);
290
- const LogMessage = require('./LogMessage');
291
- const logMessage = new LogMessage.logMessage("DEBUG", 'Error in processing snapshot files', __filename, error);
292
- addLogEventtoBuffer(logMessage);
293
- }
294
- }
295
272
  /**
296
273
  * Utilty to remove older log files.
297
274
  */
@@ -311,7 +288,7 @@ function removeOlderlogfiles() {
311
288
  return new Date(secondStat.mtime).getTime() - new Date(firstStat.mtime).getTime();
312
289
  });
313
290
  let maxLogfile = process.env.NR_CSEC_DEBUG_LOGFILE_MAX_COUNT;
314
- if(isNaN(maxLogfile)){
291
+ if (isNaN(maxLogfile)) {
315
292
  maxLogfile = 2;
316
293
  }
317
294
  for (let i = maxLogfile; i < sorted.length; i++) {
@@ -449,7 +426,7 @@ function addLogEventtoBuffer(logMessage) {
449
426
  * Utility to get framework from APM
450
427
  * @returns
451
428
  */
452
- function getFramework(){
429
+ function getFramework() {
453
430
  let framework = EMPTY_STR;
454
431
  try {
455
432
  framework = NRAgent.environment.get('Framework')[0];
@@ -459,6 +436,119 @@ function getFramework(){
459
436
  return framework;
460
437
  }
461
438
 
439
+ function listSkipDetectionCategory() {
440
+ let skipList = [];
441
+ try {
442
+ let skipCataegories = NRAgent.config.security.exclude_from_iast_scan.iast_detection_category;
443
+ for (const key in skipCataegories) {
444
+ if (skipCataegories[key]) {
445
+ skipList = skipList.concat(skip_detection_category_map[key]);
446
+ }
447
+ }
448
+ } catch (error) {
449
+ logger.error("Error while processing skip detection categories:", error);
450
+ }
451
+ return skipList;
452
+ }
453
+
454
+ function refreshAgent() {
455
+ const { Agent } = require('./agent');
456
+ if (Agent.getAgent().status.getStatus() == 'disabled' || Agent.getAgent().delayed) {
457
+ Agent.getAgent().delayed = false;
458
+ const wsClient = Agent.getAgent().client;
459
+ Agent.getAgent().status.setStatus('connecting');
460
+ wsClient.obeyReconnect();
461
+ honourDurationConfiguration();
462
+ }
463
+ }
464
+
465
+ function executeCronSchedule() {
466
+ try {
467
+ let schedule = NRAgent.config.security.scan_schedule.schedule;
468
+ if (lodash.isEmpty(schedule)) {
469
+ return;
470
+ }
471
+ logger.debug("Schedule config is set to:", schedule);
472
+ schedule = schedule.replace(/\?/g, '*');
473
+ logger.info("Security Agent scheduled time is set to:", getScheduledScanTime(Math.ceil(cron.timeout(schedule) / 60000)))
474
+ const job = new cron.CronJob(
475
+ schedule, // cronTime
476
+ function () {
477
+ logger.debug('Cron schedule invoked');
478
+ logger.info("Security Agent scheduled time is set to:", getScheduledScanTime(Math.ceil(cron.timeout(schedule) / 60000)))
479
+ refreshAgent()
480
+ }, // onTick
481
+ null, // onComplete
482
+ true, // start
483
+ );
484
+ } catch (error) {
485
+ logger.error("Error while processing schedule. Please check schedule cron expression", error);
486
+ shutDownAgent();
487
+ }
488
+
489
+ }
490
+
491
+ function honourDurationConfiguration() {
492
+ let durationFromConfig = parseInt(NRAgent.config.security.scan_schedule.duration);
493
+ let duration = durationFromConfig;
494
+ if (isNaN(duration) || duration < 0) {
495
+ duration = 0;
496
+ }
497
+ logger.debug("IAST duration is set to:", duration);
498
+ NRAgent.config.security.scan_schedule.duration = duration;
499
+ if (duration < 1) {
500
+ return;
501
+ }
502
+ logger.info("Security Agent shutdown is set to:", getScheduledScanTime(duration))
503
+ setTimeout(() => {
504
+ shutDownAgent();
505
+ }, duration * 60000);
506
+ }
507
+ /**
508
+ * Utility to send error to error inbox of APM
509
+ * @param {*} error
510
+ */
511
+ function sendErrorToErrorInbox(error) {
512
+ API.newrelic.noticeError(error);
513
+ }
514
+
515
+ const getScheduledScanTime = (delayInMinutes) => {
516
+ // Get the current time
517
+ const currentTime = new Date();
518
+
519
+ // Add the given minutes to the current time
520
+ currentTime.setMinutes(currentTime.getMinutes() + delayInMinutes);
521
+
522
+ const year = currentTime.getFullYear();
523
+ const month = currentTime.toLocaleString("default", { month: "long" });
524
+ const day = currentTime.toLocaleString("default", { weekday: "long" });
525
+ const date = currentTime.getDate();
526
+ const hours = currentTime.getHours();
527
+ const minutes = currentTime.getMinutes();
528
+ const seconds = currentTime.getSeconds();
529
+ const futureUpdatedTime = `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
530
+ const futureDateTime = `${day}, ${month} ${date} ${year} ${futureUpdatedTime}`;
531
+ return futureDateTime
532
+ };
533
+
534
+ function shutDownAgent() {
535
+ const { Agent } = require('./agent');
536
+ if (NRAgent.config.security.scan_schedule.always_sample_traces) {
537
+ Agent.getAgent().delayed = true;
538
+ logger.warn('Scan duration completed, IAST going under hibernate mode')
539
+ return;
540
+ }
541
+ if (Agent.getAgent().status.getStatus() === 'disabled') {
542
+ return;
543
+ }
544
+ Agent.getAgent().status.setStatus('disabled');
545
+ const wsClient = Agent.getAgent().client;
546
+ wsClient.closeWS();
547
+ logger.warn("Security Agent status is disabled");
548
+ }
549
+
550
+
551
+
462
552
 
463
553
  module.exports = {
464
554
  getUUID,
@@ -475,7 +565,6 @@ module.exports = {
475
565
  getHCStats,
476
566
  isAgentActiveState,
477
567
  iastRestClientStatus,
478
- removeOlderSnapshots,
479
568
  logRollOver,
480
569
  getValidatorServiceEndpointURL,
481
570
  getCSECmode,
@@ -484,5 +573,12 @@ module.exports = {
484
573
  setWSHealthStatus,
485
574
  addLogEventtoBuffer,
486
575
  getLogEvents,
487
- getFramework
576
+ getFramework,
577
+ listSkipDetectionCategory,
578
+ executeCronSchedule,
579
+ honourDurationConfiguration,
580
+ scanStartTime,
581
+ trafficStartedTime,
582
+ sendErrorToErrorInbox,
583
+ getScheduledScanTime,
488
584
  };
@@ -0,0 +1,61 @@
1
+ /*
2
+ * Copyright 2024 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: New Relic Software License v1.0
4
+ */
5
+
6
+ 'use strict'
7
+
8
+ const { HttpsProxyAgent } = require('https-proxy-agent')
9
+ const logs = require('../../logging');
10
+ let logger = logs.getLogger();
11
+ const commonUtils = require('../../commonUtils');
12
+ const fs = require('fs');
13
+
14
+ let agentProxyWithKeepAlive = null
15
+
16
+ exports.proxyAgent = function proxyAgent(config) {
17
+ if (null !== agentProxyWithKeepAlive) {
18
+ return agentProxyWithKeepAlive
19
+ }
20
+ const proxyUrl = proxyOptions(config)
21
+ let proxyOpts = {
22
+ secureEndpoint: config.ssl,
23
+ auth: proxyUrl.auth,
24
+ ca: config?.certificates?.length ? config.certificates : [],
25
+ keepAlive: true
26
+ }
27
+ let cert = '';
28
+ try {
29
+ const certPath = commonUtils.getPathOfCACert();
30
+ cert = fs.readFileSync(certPath, 'utf8');
31
+ } catch (error) {
32
+ logger.error("Error in reading certificate:", error);
33
+
34
+ }
35
+ proxyOpts.ca.push(cert);
36
+ logger.info(`Using proxy: ${proxyUrl}`)
37
+ agentProxyWithKeepAlive = new HttpsProxyAgent(proxyUrl, proxyOpts)
38
+ return agentProxyWithKeepAlive
39
+ }
40
+
41
+ /**
42
+ * Utility to create proxy URL
43
+ * @param config
44
+ * @returns
45
+ */
46
+ function proxyOptions(config) {
47
+ let proxyUrl
48
+ if (config.proxy) {
49
+ proxyUrl = config.proxy
50
+ } else {
51
+ proxyUrl = 'https://'
52
+ let proxyAuth = config.proxy_user
53
+ if (config.proxy_pass !== '') {
54
+ proxyAuth += ':' + config.proxy_pass
55
+ proxyUrl += `${proxyAuth}@`
56
+ }
57
+
58
+ proxyUrl += `${config.proxy_host || 'localhost'}:${config.proxy_port || 80}`
59
+ }
60
+ return proxyUrl
61
+ }
@@ -6,8 +6,13 @@ const { Agent } = require('../../../agent');
6
6
  let pendingRequestIds = new Set();
7
7
  let completedRequestsMap = new Map();
8
8
  const PolicyManager = require('../../../Policy');
9
+ const API = require('../../../../../../nr-security-api');
9
10
  let batchSize;
10
- const batchthreshold = 160;
11
+ const batchthreshold = 200;
12
+ const logs = require('../../../logging');
13
+ let logger = logs.getLogger();
14
+ const commonUtils = require('../../../commonUtils');
15
+
11
16
  function getPendingRequestIds() {
12
17
  return [...pendingRequestIds];
13
18
  }
@@ -31,7 +36,7 @@ function completedRequestsMapInit(id) {
31
36
 
32
37
  function addCompletedRequests(id, eventId) {
33
38
  let data = completedRequestsMap.get(id);
34
- if(!data){
39
+ if (!data) {
35
40
  return;
36
41
  }
37
42
  data.push(eventId);
@@ -42,20 +47,21 @@ function getCompletedRequestsMap() {
42
47
  return completedRequestsMap;
43
48
  }
44
49
 
45
- function clearCompletedRequestMap(){
50
+ function clearCompletedRequestMap() {
46
51
  completedRequestsMap.clear();
47
52
  }
48
53
 
49
- function clearPendingRequestIdSet(){
54
+ function clearPendingRequestIdSet() {
50
55
  pendingRequestIds.clear();
51
56
  }
52
57
 
53
- function IASTCleanup(){
58
+ function IASTCleanup() {
54
59
  clearCompletedRequestMap();
55
60
  clearPendingRequestIdSet();
56
61
  }
57
62
 
58
63
  function generateIASTDataRequest() {
64
+
59
65
  const policyInstance = PolicyManager.getInstance();
60
66
  if (policyInstance.data && policyInstance.data.vulnerabilityScan && policyInstance.data.vulnerabilityScan.iastScan) {
61
67
  batchSize = batchSize ? batchSize : policyInstance.data.vulnerabilityScan.iastScan.probing.batchSize;
@@ -64,11 +70,33 @@ function generateIASTDataRequest() {
64
70
  }
65
71
  }
66
72
  if (getCompletedRequestsMap().size >= batchSize || batchSize < batchthreshold || getPendingRequestIds().length < batchSize) {
67
- batchSize = (2 * batchSize);
73
+ batchSize = (2 * batchSize) - getPendingRequestIds().length;
74
+ }
75
+
76
+ const NRAgent = API.getNRAgent();
77
+ let scanRateLimit = 3600;
78
+ let scanRateLimitFromConfig = parseInt(NRAgent.config.security.scan_controllers.iast_scan_request_rate_limit);
79
+ scanRateLimit = scanRateLimitFromConfig
80
+ if (isNaN(scanRateLimitFromConfig)) {
81
+ scanRateLimit = 3600;
68
82
  }
83
+ if (scanRateLimit >= 0 || scanRateLimit < 0) {
84
+ batchSize = parseInt(scanRateLimit / 12);
85
+ if (scanRateLimit < 12) {
86
+ batchSize = 1;
87
+ } else if (scanRateLimit > 3600) {
88
+ batchSize = 300;
89
+ }
90
+ }
91
+
69
92
  let object = {};
70
93
  object['jsonName'] = 'iast-data-request';
71
94
  object['applicationUUID'] = Agent.getAgent().applicationInfo.applicationUUID;
95
+ object['appEntityGuid'] = Agent.getAgent().applicationInfo.appEntityGuid;
96
+ object['appAccountId'] = Agent.getAgent().applicationInfo.appAccountId;
97
+ if (batchSize && batchSize > 100) {
98
+ batchSize = 100;
99
+ }
72
100
  object["batchSize"] = batchSize ? batchSize : 300;
73
101
  object['pendingRequestIds'] = getPendingRequestIds();
74
102
  object['completedRequests'] = Object.fromEntries(getCompletedRequestsMap());
@@ -21,10 +21,12 @@ const LogMessage = require('../../../LogMessage');
21
21
  require('dns').setDefaultResultOrder('ipv4first')
22
22
  const PolicyManager = require('../../../Policy');
23
23
 
24
- const statusUtils = require('../../../statusUtils');
25
24
 
26
25
  const find = `${SLASH}{{NR_CSEC_VALIDATOR_HOME_TMP}}`;
27
26
  const CSEC_HOME_TMP_CONST = new RegExp(find, 'g');
27
+ const commonUtils = require('../../../commonUtils');
28
+
29
+ const CSEC_HOME_TMP_CONST_ENCODED = new RegExp('%7B%7BNR_CSEC_VALIDATOR_HOME_TMP%7D%7D', 'g');
28
30
 
29
31
  let logger;
30
32
  let lastFuzzEventTime = 0;
@@ -32,13 +34,26 @@ let iastIntervalConst;
32
34
  let coolDownIntervalConst;
33
35
  let additionalCoolDownTime = 0;
34
36
  let fuzzedApiIDSet = new Set();
37
+ const API = require('../../../../../../nr-security-api');
38
+ const NRAgent = API.getNRAgent();
35
39
 
36
40
 
37
41
  /**
38
42
  * utility to start IAST Schedular
39
43
  */
40
44
  function startIASTSchedular() {
41
- Agent.getAgent().client.dispatcher(IASTUtil.generateIASTDataRequest());
45
+ if (Agent.getAgent().delayed) {
46
+ let delayFromConfig = parseInt(NRAgent.config.security.scan_schedule.delay);
47
+ let delay = delayFromConfig;
48
+ if (isNaN(delay) || delay < 0) {
49
+ delay = 0;
50
+ }
51
+ // logger.debug("IAST data pull request is scheduled at %s", require('../../../commonUtils').getScheduledScanTime(delay))
52
+ }
53
+ if (!Agent.getAgent().delayed) {
54
+ Agent.getAgent().client.dispatcher(IASTUtil.generateIASTDataRequest());
55
+ }
56
+
42
57
  if (iastIntervalConst) {
43
58
  clearInterval(iastIntervalConst);
44
59
  }
@@ -51,8 +66,11 @@ function startIASTSchedular() {
51
66
  if (isNaN(probingInterval)) {
52
67
  probingInterval = 5;
53
68
  }
54
-
69
+
55
70
  iastIntervalConst = setInterval(() => {
71
+ if (Agent.getAgent().status.getStatus() == 'disabled' || Agent.getAgent().delayed) {
72
+ return;
73
+ }
56
74
  let data = IASTUtil.generateIASTDataRequest();
57
75
  let currentTime = Date.now();
58
76
  let completedListSize = IASTUtil.getCompletedRequestsMap().size;
@@ -87,9 +105,19 @@ function logScannedApiId(fuzzHeader, requestURL) {
87
105
 
88
106
  // handler function to parse fuzz event and prepare fuzz request
89
107
  function handler(json) {
108
+ if (Agent.getAgent().status.getStatus() == 'disabled') {
109
+ return;
110
+ }
90
111
  setLastFuzzEventTime();
91
112
  let rawFuzzRequest = json.arguments[0];
92
- rawFuzzRequest = rawFuzzRequest.replace(CSEC_HOME_TMP_CONST, CSEC_HOME_TMP);
113
+
114
+ try {
115
+ rawFuzzRequest = rawFuzzRequest.replace(CSEC_HOME_TMP_CONST, CSEC_HOME_TMP);
116
+ rawFuzzRequest = rawFuzzRequest.replace(CSEC_HOME_TMP_CONST_ENCODED, encodeURI(CSEC_HOME_TMP));
117
+ } catch (error) {
118
+ logger.debug("Error while replacing place holder", error);
119
+ }
120
+
93
121
  let fuzzRequest;
94
122
  try {
95
123
  fuzzRequest = JSON.parse(rawFuzzRequest);
@@ -97,7 +125,7 @@ function handler(json) {
97
125
  IASTUtil.addPendingRequestId(json.id);
98
126
  } catch (error) {
99
127
  logger.error('Parsing exeception in fuzz request: ', error);
100
-
128
+
101
129
  const logMessage = new LogMessage.logMessage(SEVERE, 'Parsing exeception in fuzz request', __filename, error);
102
130
  require('../../../commonUtils').addLogEventtoBuffer(logMessage);
103
131
  }
@@ -158,7 +186,6 @@ function handleFuzzRequest(fuzzDetails) {
158
186
  handleFuzzResponse(response, fuzzDetails);
159
187
  }
160
188
  } catch (err) {
161
- statusUtils.addErrortoBuffer(err);
162
189
  const fuzzFailEvent = new FuzzFailEvent(fuzzRequest.headers[NR_CSEC_FUZZ_REQUEST_ID]);
163
190
  logger.error(stringify(fuzzFailEvent));
164
191
  try {
@@ -179,6 +206,9 @@ function handleFuzzResponse(response, fuzzDetails) {
179
206
  const { rawFuzzRequest, fuzzRequest } = fuzzDetails;
180
207
  if (response) {
181
208
  IASTUtil.removePendingRequestId(fuzzRequest.id);
209
+ if (commonUtils.scanStartTime == 0) {
210
+ commonUtils.scanStartTime = Date.now();
211
+ }
182
212
  response.then(() => {
183
213
  logger.info('Fuzz success: ' + rawFuzzRequest);
184
214
  }).catch(() => {
@@ -10,6 +10,10 @@ const initLogger = logs.getInitLogger();
10
10
  const LOG_MESSAGES = require('../../../sec-agent-constants').LOG_MESSAGES;
11
11
  const applicationInfoModule = require('../../../applicationinfo');
12
12
  const LogMessage = require('../../../LogMessage');
13
+ const API = require('../../../../../../nr-security-api');
14
+ const NRAgent = API.getNRAgent();
15
+ const { Agent } = require('../../../agent');
16
+
13
17
 
14
18
  module.exports.handler = function handler(json) {
15
19
  try {
@@ -20,7 +24,7 @@ module.exports.handler = function handler(json) {
20
24
  initLogger.info('Security Agent is now ACTIVE for', applicationInfoModule.getInstance().applicationUUID);
21
25
  const logMessage = new LogMessage.logMessage("INFO", `Security Agent is ACTIVE for ${ applicationInfoModule.getInstance().applicationUUID}`, __filename, null);
22
26
  require('../../../commonUtils').addLogEventtoBuffer(logMessage);
23
-
27
+
24
28
  } catch (error) {
25
29
  logger.error(LOG_MESSAGES.PARSING_EXP_WELCOME_MSG, error);
26
30
  }
@@ -4,11 +4,14 @@
4
4
  */
5
5
 
6
6
  let logger;
7
+ const { Agent } = require('../../../agent');
7
8
  module.exports.handler = function handler (json) {
8
- logger.info('WS reconnect received', json);
9
- const { Agent } = require('../../../agent');
10
- const wsClient = Agent.getAgent().client;
11
- wsClient.obeyReconnect();
9
+ if (Agent.getAgent().status.getStatus() != 'disabled'){
10
+ logger.info('WS reconnect received', json);
11
+ const wsClient = Agent.getAgent().client;
12
+ wsClient.obeyReconnect();
13
+ }
14
+
12
15
  };
13
16
 
14
17
  module.exports.setLogger = l => { logger = l };
@@ -17,11 +17,11 @@ const hc = require('../../health-check');
17
17
  const fs = require('fs');
18
18
  const { promisify } = require('../../sec-util');
19
19
  const ResponseHandler = require('./response');
20
- const { EMPTY_APPLICATION_UUID, LOG_MESSAGES, CSEC_SEP, NR_CSEC_FUZZ_REQUEST_ID, EXITEVENT, JSON_NAME, RASP, SEVERE } = require('../../sec-agent-constants');
21
- const statusUtils = require('../../statusUtils');
20
+ const { EMPTY_APPLICATION_UUID, LOG_MESSAGES, CSEC_SEP, NR_CSEC_FUZZ_REQUEST_ID, EXITEVENT, JSON_NAME, SEVERE } = require('../../sec-agent-constants');
22
21
  const commonUtils = require('../../commonUtils');
23
22
  const IASTUtil = require('../websocket/response/IASTUtils');
24
23
  const LogMessage = require('../../LogMessage');
24
+ const proxyUtil = require('./proxy-util');
25
25
 
26
26
  const BUSY = 'busy';
27
27
  const IDLE = 'idle';
@@ -105,18 +105,25 @@ SecWebSocket.prototype.init = function init() {
105
105
  const authHeaders = require('../../Auth-headers').getInstance();
106
106
  initLogger.info(`Connecting to Validator at ${validatorService}`);
107
107
  IASTUtil.IASTCleanup();
108
- let cert = ''
108
+ let cert = '';
109
109
  try {
110
110
  const certPath = commonUtils.getPathOfCACert();
111
111
  cert = fs.readFileSync(certPath, 'utf8');
112
112
  } catch (error) {
113
113
  logger.error("Error in reading certificate:", error);
114
+ commonUtils.sendErrorToErrorInbox(error)
114
115
  const logMessage = new LogMessage.logMessage(SEVERE, 'Error in reading certificate for websocket', __filename, error);
115
116
  commonUtils.addLogEventtoBuffer(logMessage);
116
117
 
117
118
  }
118
-
119
- webSocket = new WebSocket(validatorService, { headers: authHeaders, cert: cert, handshakeTimeout: 10000 });
119
+ const isProxy = !!(NRAgent.config.proxy || NRAgent.config.proxy_port || NRAgent.config.proxy_host)
120
+ if(isProxy){
121
+ const agentWithProxy = proxyUtil.proxyAgent(NRAgent.config);
122
+ webSocket = new WebSocket(validatorService, { headers: authHeaders, cert: cert, handshakeTimeout: 10000, agent:agentWithProxy });
123
+ }
124
+ else{
125
+ webSocket = new WebSocket(validatorService, { headers: authHeaders, cert: cert, handshakeTimeout: 10000 });
126
+ }
120
127
 
121
128
  webSocket.on(WS_ON_OPEN, this.openCB);
122
129
  webSocket.on(WS_ON_MSG, this.msgCB);
@@ -162,12 +169,16 @@ SecWebSocket.prototype.reconnect = function reconnect() {
162
169
  return;
163
170
  }
164
171
  commonUtils.setWSHealthStatus('Error');
172
+ commonUtils.sendErrorToErrorInbox(new Error("Unable to connect to Security Engine"))
165
173
  logger.debug(LOG_MESSAGES.DETECTED_BROKEN_CONN);
166
174
  this.obeyReconnect();
167
175
 
168
176
  };
169
177
 
170
178
  SecWebSocket.prototype.obeyReconnect = function obeyReconnect() {
179
+ if (Agent.getAgent().status.getStatus() == 'disabled') {
180
+ return;
181
+ }
171
182
  const { instance } = this;
172
183
  if (initTimeOut) {
173
184
  clearTimeout(initTimeOut);
@@ -186,13 +197,25 @@ SecWebSocket.prototype.obeyReconnect = function obeyReconnect() {
186
197
 
187
198
  }
188
199
 
200
+ SecWebSocket.prototype.closeWS = function closeWS() {
201
+ const { instance } = this;
202
+ try {
203
+ instance.close();
204
+ } catch (error) {
205
+ logger.error("Error while closing websocket", error);
206
+ }
207
+ }
208
+
189
209
  SecWebSocket.prototype.pingWS = async function pingWS() {
210
+ if (Agent.getAgent().status.getStatus() != 'active') {
211
+ return;
212
+ }
190
213
  const self = this;
191
214
  let currentTime = Date.now();
192
215
 
193
216
  let timeDiffInPing = (currentTime - lastPongtime) / 1000;
194
- logger.debug("Websocket ready state is:",self.instance.readyState)
195
-
217
+ logger.debug("Websocket ready state is:", self.instance.readyState)
218
+
196
219
  if (timeDiffInPing > 40 && lastPongtime != 0 && self.instance.readyState > 1) {
197
220
  self.obeyReconnect();
198
221
  lastPongtime = 0;
@@ -204,13 +227,11 @@ SecWebSocket.prototype.pingWS = async function pingWS() {
204
227
  if (err) {
205
228
  logger.debug("Error while pinging:", err);
206
229
  commonUtils.setWSHealthStatus('Error');
207
- statusUtils.addErrortoBuffer(err);
208
230
 
209
231
  }
210
232
  });
211
233
  } catch (err) {
212
234
  logger.debug("error in ping:", err);
213
- statusUtils.addErrortoBuffer(err);
214
235
  commonUtils.setWSHealthStatus('Error');
215
236
  return;
216
237
  }
@@ -266,7 +287,6 @@ SecWebSocket.prototype.dispatch = async function dispatch(event) {
266
287
  })
267
288
  } catch (error) {
268
289
  logger.debug(LOG_MESSAGES.ERROR_WHILE_SEND_EVENT, eventStr, error);
269
- statusUtils.addErrortoBuffer(error);
270
290
  handleDispatchFailure(this, event, eventStr);
271
291
  }
272
292
  };
@@ -286,7 +306,6 @@ SecWebSocket.prototype.dispatchApplicationInfo = async function dispatchApplicat
286
306
  try {
287
307
  await promisify(this.instance, this.instance.send)(eventStr, { mask: true });
288
308
  } catch (error) {
289
- statusUtils.addErrortoBuffer(error);
290
309
  logger.warn('Error while sending applicationInfo:', error);
291
310
  this.obeyReconnect();
292
311
  }
@@ -325,7 +344,6 @@ SecWebSocket.prototype.flushEventQueue = async function flushEventQueue() {
325
344
  const results = await Promise.all(sentEvents);
326
345
  hc.getInstance().registerEventsSent(results.length);
327
346
  } catch (err) {
328
- statusUtils.addErrortoBuffer(err);
329
347
  logger.debug('Flush failed, reception of all events on IC couldn\'t be ensured.');
330
348
  }
331
349
  };
@@ -398,7 +416,7 @@ const defaultOnOpenCB = () => async function onOpen() {
398
416
  initLogger.info(LOG_MESSAGES.SENDING_APPINFO_COMPLETE, JSON.stringify(applicationInfo));
399
417
  } catch (err) {
400
418
  logger.error(`Connection broken: ${err.message}`);
401
- statusUtils.addErrortoBuffer(err);
419
+ commonUtils.sendErrorToErrorInbox(err);
402
420
  commonUtils.setWSHealthStatus('Error')
403
421
  setWebSocketConn();
404
422
  self.setValidatorNotReadyForEvents();
@@ -431,10 +449,10 @@ const defaultOnMsgCB = () => function onMessage(data) {
431
449
  */
432
450
  const defaultOnErrCB = () => function onClose(error) {
433
451
  commonUtils.setWSHealthStatus('Error');
434
- statusUtils.addErrortoBuffer(error);
435
452
  const self = this;
436
453
  logger.error("Error while connecting to validator:", error.message)
437
454
  const logMessage = new LogMessage.logMessage(SEVERE, 'Error while connecting to validator', __filename, error);
455
+ commonUtils.sendErrorToErrorInbox(error);
438
456
  commonUtils.addLogEventtoBuffer(logMessage);
439
457
  logger.warn("Security Agent INACTIVE!!!")
440
458
  if (error && error.code && (error.code === 'ECONNREFUSED' || error.code === 'EPIPE' || error.code === 'ECONNRESET')) {