@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
package/index.js ADDED
@@ -0,0 +1,24 @@
1
+ /*
2
+ * Copyright 2023 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ const API = require('./lib/nr-security-api');
7
+ /**
8
+ * Entry point of CSEC agent.
9
+ * @param {*} agent newrelic agent object
10
+ * @returns
11
+ */
12
+ function start(NRAgentObject) {
13
+ const agent = NRAgentObject.agent;
14
+ API.newrelic = NRAgentObject;
15
+ API.setNRAgent(agent);
16
+ if (!agent.config.security.agent.enabled || agent.config.security.enabled == null) {
17
+ return;
18
+ }
19
+ require('./lib/nr-security-agent');
20
+ }
21
+ module.exports = {
22
+ API,
23
+ start
24
+ }
@@ -0,0 +1,66 @@
1
+
2
+ /*
3
+ * Copyright 2023 New Relic Corporation. All rights reserved.
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const AWS_LAMBDA_NODE_EXEC_ENV_IDENTIFIER = /^AWS_Lambda_nodejs.*$/g;
10
+ const AWS_EXECUTION_ENV_VAR = 'AWS_EXECUTION_ENV';
11
+
12
+ module.exports = {
13
+
14
+ COLLECTOR_TYPE: 'NODE',
15
+ LANGUAGE: 'JavaScript',
16
+ AWS_LAMBDA_QUALIFIED_ARN_ENV_IDENTIFIER: 'AWS_LAMBDA_ARN',
17
+ AWS_LAMBDA_FUNCTION_NAME_ENV_IDENTIFIER: 'AWS_LAMBDA_FUNCTION_NAME',
18
+ AWS_LAMBDA_FUNCTION_VERSION_ENV_IDENTIFIER: 'AWS_LAMBDA_FUNCTION_VERSION',
19
+ AWS_SESSION_TOKEN_ENV_IDENTIFIER: 'AWS_SESSION_TOKEN',
20
+ LAMBDA_TASK_ROOT_ENV_IDENTIFIER: 'LAMBDA_TASK_ROOT',
21
+ LAMBDA_ENABLE_RESPONSE_BLOCKING: 'LAMBDA_ENABLE_RESPONSE_BLOCKING',
22
+ AWS_LAMBDA_NODE_EXEC_ENV_IDENTIFIER,
23
+ AWS_EXECUTION_ENV_VAR,
24
+ IS_LAMBDA_ENV: Array.isArray(
25
+ (process.env[AWS_EXECUTION_ENV_VAR] || '').match(AWS_LAMBDA_NODE_EXEC_ENV_IDENTIFIER)
26
+ ),
27
+ LAMBDA_RUNTIME_DIR_VAR: 'LAMBDA_RUNTIME_DIR',
28
+ EMPTY_APPLICATION_UUID: '--0--',
29
+ QUESTIONMARK: '?',
30
+ PIPE_SEP: '|',
31
+ ATTHERATE: '@',
32
+ EMPTY_STR: '',
33
+ COLON: ':',
34
+ OPEN_PARANTHESIS: '(',
35
+ CLOSE_PARANTHESIS: ')',
36
+ SLASH: '/',
37
+ INCOMING_MSG: 'IncomingMessage',
38
+ OBJECT: 'object',
39
+ STRING: 'string',
40
+ TRIGGER_VIA_RCI: 'triggerViaRCI',
41
+ RCI_METHOD_CALLS: 'rciMethodsCalls',
42
+ VULNERABLE: 'VULNERABLE',
43
+ UTF8: 'utf8',
44
+ CONTENT_TYPE: 'content-type',
45
+ TEXT_HTML: 'text/html',
46
+ APPLICATION_JSON: 'application/json',
47
+ APPLICATION_XML: 'application/xml',
48
+ APPLICATION_XHTML: 'application/xhtml+xml',
49
+ TEXT_PLAIN: 'text/plain',
50
+ APPLICATION_X_FORM_URLENCODED: 'application/x-www-form-urlencoded',
51
+ MULTIPART_FORM_DATA: 'multipart/form-data',
52
+ XFORFOR: 'x-forwarded-for',
53
+ DOUBLE_DOLLAR: '$$',
54
+ LOADING_MODULE: 'Loading module ',
55
+ EMPTY_STRING: '',
56
+ QUESTION_MARK: '?',
57
+ DOUBLE_PIPE: '||',
58
+ DOTDOTSLASH: '../',
59
+ SLASHDOTDOT: '/..',
60
+ UNDEFINED: 'undefined',
61
+ SELF_FD_PATH: '/proc/self/fd/',
62
+ SLASH: '/',
63
+ CSEC_LAST_FUZZ_REQUEST_TIME: 'CSEC_LAST_FUZZ_REQUEST_TIME',
64
+ NR_CSEC_FUZZ_REQUEST_ID: 'nr-csec-fuzz-request-id',
65
+
66
+ };
@@ -0,0 +1,49 @@
1
+
2
+ /*
3
+ * Copyright 2023 New Relic Corporation. All rights reserved.
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ const EVENT_TYPE = {
8
+ SYSTEM_COMMAND: 'SYSTEM_COMMAND',
9
+ SYSTEM_EXIT: 'SYSTEM_EXIT',
10
+ FILE_OPERATION: 'FILE_OPERATION',
11
+ FILE_INTEGRITY: 'FILE_INTEGRITY',
12
+ DB_COMMAND: 'SQL_DB_COMMAND',
13
+ NOSQL_DB_COMMAND: 'NOSQL_DB_COMMAND',
14
+ HTTP_REQUEST: 'HTTP_REQUEST',
15
+ CODE_INJECTION: 'CODE_INJECTION',
16
+ XXE: 'XXE',
17
+ CIPHER: 'CIPHER',
18
+ HASH: 'HASH',
19
+ RANDOM: 'RANDOM',
20
+ UNVALIDATED_REDIRECT: 'UNVALIDATED_REDIRECT',
21
+ REFLECTED_XSS: 'REFLECTED_XSS',
22
+ XPATH: 'XPATH',
23
+ LDAP: 'LDAP'
24
+ }
25
+ const EVENT_CATEGORY = {
26
+ MYSQL: 'MYSQL',
27
+ POSTGRES: 'POSTGRES',
28
+ ORACLE: 'ORACLE',
29
+ MONGO: 'MONGO',
30
+ MSSQL: 'MSSQL',
31
+ SQLITE: 'SQLITE',
32
+ FILE: 'FILE',
33
+ SYS: 'SYSTEM',
34
+ HTTP: 'HTTP',
35
+ CODE_INJECTION: 'CODE_INJECTION',
36
+ XXE: 'XXE',
37
+ CRYPTO: 'CRYPTO',
38
+ HASH: 'HASH',
39
+ WEAKRANDOM: 'WEAKRANDOM',
40
+ UNVALIDATED_REDIRECT: 'UNVALIDATED_REDIRECT',
41
+ REFLECTED_XSS: 'REFLECTED_XSS',
42
+ XPATH: 'XPATH',
43
+ LDAP: 'LDAP'
44
+ }
45
+
46
+ module.exports = {
47
+ EVENT_CATEGORY,
48
+ EVENT_TYPE
49
+ }
@@ -0,0 +1,73 @@
1
+ /*
2
+ * Copyright 2023 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ const requestMap = new Map();
7
+
8
+ /**
9
+ * Utility to get request by transaction Id
10
+ * @param {*} id
11
+ * @returns
12
+ */
13
+ function getRequestFromId(id) {
14
+ return requestMap.get(id);
15
+ }
16
+
17
+ /**
18
+ * Utility function to set request data corresponding to transacation Id
19
+ * @param {*} id
20
+ * @param {*} requestData
21
+ */
22
+ function setRequest(id, requestData) {
23
+ requestMap.set(id, requestData);
24
+ }
25
+
26
+ /**
27
+ * Utility to get request using shim
28
+ * @param {*} shim
29
+ * @returns
30
+ */
31
+ function getRequest(shim) {
32
+ const segment = shim.getActiveSegment();
33
+ if (segment) {
34
+ const transactionId = segment.transaction.id;
35
+ return getRequestFromId(transactionId);
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Utility to update request body
41
+ * @param {*} shim
42
+ * @param {*} data
43
+ */
44
+ function updateRequestBody(shim, data) {
45
+ const segment = shim.getActiveSegment();
46
+ if (segment) {
47
+ const transactionId = segment.transaction.id;
48
+ const requestData = getRequestFromId(transactionId);
49
+ if (requestData) {
50
+ requestData.body = data;
51
+ setRequest(transactionId, requestData);
52
+ }
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Utility to clear data based on transaction Id
58
+ * @param {*} transactionId
59
+ */
60
+ function gcRequestMap(transactionId) {
61
+ if (requestMap.has(transactionId)) {
62
+ requestMap.delete(transactionId);
63
+ }
64
+ }
65
+
66
+ module.exports = {
67
+ getRequestFromId,
68
+ getRequest,
69
+ setRequest,
70
+ updateRequestBody,
71
+ gcRequestMap,
72
+ requestMap
73
+ }
@@ -0,0 +1,30 @@
1
+ /*
2
+ * Copyright 2023 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+
7
+ const routeMap = new Map();
8
+ /**
9
+ * Utility to set route based on key value pair
10
+ * @param {*} key
11
+ * @param {*} value
12
+ */
13
+ function setRoute(key, value){
14
+ routeMap.set(key,value);
15
+ }
16
+
17
+ /**
18
+ * Utility to get route corresponding to key
19
+ * @param {*} key
20
+ * @returns
21
+ */
22
+ function getRoute(key){
23
+ return routeMap.get(key);
24
+ }
25
+
26
+ module.exports={
27
+ getRoute,
28
+ setRoute,
29
+ routeMap
30
+ }
@@ -0,0 +1,134 @@
1
+ /*
2
+ * Copyright 2023 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ const path = require('path');
7
+ const API = require("../../nr-security-api");
8
+ const NRAgent = API.getNRAgent();
9
+ const AGENT_DIR = path.join(__dirname, '../../');
10
+ const NR_LIB = '/newrelic/lib';
11
+ let LOAD_LIST;
12
+ const { IS_LAMBDA_ENV, LAMBDA_RUNTIME_DIR_VAR } = require('./constants');
13
+ const LAMBDA_RUNTIME_DIR = process.env[LAMBDA_RUNTIME_DIR_VAR];
14
+ const PROMISE_SEPERATOR = '---------------------------------------------';
15
+ const ANONYMOUS_FUNCTION = '<anonymous>';
16
+ const NODE_MODULES_LITERAL = 'node_modules';
17
+ const OPEN_BRACKET = '(';
18
+ const CLOSE_BRACKET = ')';
19
+ const COLON = ':';
20
+ const ACYNC_HOOKS = 'async_hooks.js';
21
+ const RUNINASYNCSCOPE = 'runInAsyncScope';
22
+
23
+ /**
24
+ * Synchronously prints the stack trace from provided trace
25
+ * and extract user script.
26
+ *
27
+ * @param {*} trace
28
+ * @param {*} currentFile
29
+ *
30
+ * @returns {*} detected source info
31
+ */
32
+ function getSourceDetailsFromTrace (trace, currentFile, stakTrace) {
33
+ const info = {};
34
+ let sourceCaptured = false;
35
+ let evalObj;
36
+ let evalFlag = true;
37
+ let getEvalOrigin;
38
+ let isEval = false;
39
+ for (let i = 0; i < trace.length && i < 20; i++) {
40
+ const funcName = trace[i].getFunctionName();
41
+ const fileName = trace[i].getFileName();
42
+ const lineNumber = trace[i].getLineNumber();
43
+
44
+ if (NRAgent && NRAgent.config.security.detection.rci.enabled && NRAgent.config.security.detection.deserialization.enabled) {
45
+ getEvalOrigin = trace[i].getEvalOrigin();
46
+ isEval = trace[i].isEval();
47
+ }
48
+
49
+ let prevMethodName = null;
50
+ if (i > 0 && isEval) {
51
+ const mname = trace[i - 1].getMethodName();
52
+ prevMethodName = mname || trace[i - 1].getFunctionName();
53
+ }
54
+
55
+ if (isEval && evalFlag && NRAgent && NRAgent.config.security.detection.rci.enabled && NRAgent.config.security.detection.deserialization.enabled) {
56
+ const serachStr = prevMethodName + OPEN_BRACKET + trace[i - 1].getFileName() + COLON + trace[i - 1].getLineNumber() + CLOSE_BRACKET;
57
+ evalObj = computeTrace(getEvalOrigin, prevMethodName, stakTrace, serachStr);
58
+ evalFlag = false;
59
+ }
60
+ if (fileName && !fileName.includes(AGENT_DIR) && !fileName.includes(NR_LIB) &&
61
+ !fileName.includes(PROMISE_SEPERATOR) &&
62
+ !isLambdaRuntimeFile(fileName)
63
+ ) {
64
+
65
+ if (!sourceCaptured) {
66
+ info.source = {
67
+ funcName: prevMethodName || ((funcName) || ANONYMOUS_FUNCTION),
68
+ fileName: fileName,
69
+ lineNumber: lineNumber
70
+ };
71
+ sourceCaptured = true;
72
+ }
73
+ if (!fileName.includes(NODE_MODULES_LITERAL) && !LOAD_LIST.includes(fileName) && !fileName.includes('node:') && !fileName.includes(NR_LIB)) {
74
+ info.fileName = fileName;
75
+ info.funcName = ((funcName) || ANONYMOUS_FUNCTION);
76
+ info.lineNumber = lineNumber;
77
+ // break;
78
+ }
79
+ }
80
+ }
81
+
82
+ if (!info.fileName && sourceCaptured) {
83
+ info.fileName = info.source.fileName;
84
+ info.funcName = ((info.source.funcName) ? info.source.funcName : ANONYMOUS_FUNCTION);
85
+ info.lineNumber = info.source.lineNumber;
86
+ }
87
+ if (evalObj) {
88
+ info.evalObj = evalObj;
89
+ }
90
+ return info;
91
+ }
92
+
93
+
94
+ function isLambdaRuntimeFile (fileName) {
95
+ return IS_LAMBDA_ENV && fileName.includes(LAMBDA_RUNTIME_DIR);
96
+ }
97
+
98
+ /**
99
+ * Sets the load list.
100
+ *
101
+ * @param {*} list
102
+ */
103
+ const setLoadList = list => {
104
+ LOAD_LIST = list;
105
+ };
106
+
107
+
108
+ function computeTrace (traceLine, apiCall, stakTrace, serachStr) {
109
+ const regex = /^(?:\s*at )?(?:(new) )?(?:(.*?) \()?(?:eval at ([^ ]+) \((.+?):(\d+):(\d+)\), )?(?:(.+?):(\d+):(\d+)|(native))(\)?)$/;
110
+ const evalObj = {};
111
+ try {
112
+ const line = traceLine.match(regex);
113
+ evalObj.apiCall = apiCall;
114
+ if (line) {
115
+ evalObj.funcName = line[2];
116
+ evalObj.fileName = line[7];
117
+ evalObj.lineNumber = line[8];
118
+ const indexUpTo = stakTrace.indexOf(serachStr);
119
+ const apicalls = stakTrace.slice(0, indexUpTo + 1);
120
+ if (indexUpTo == -1) {
121
+ apicalls.push(serachStr);
122
+ }
123
+ evalObj.invokedCalls = apicalls;
124
+ }
125
+ } catch (error) {
126
+ }
127
+
128
+ return evalObj;
129
+ }
130
+
131
+ module.exports = {
132
+ getSourceDetailsFromTrace,
133
+ setLoadList
134
+ }
@@ -0,0 +1,212 @@
1
+ /*
2
+ * Copyright 2023 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ const stackTraceModule = require('./stack-trace');
7
+ const path = require('path');
8
+ const secTrace = require('./sec-trace');
9
+ const requestManager = require('./request-manager');
10
+ const routeManager = require('./route-manager');
11
+ const async_hooks = require('async_hooks');
12
+
13
+ const AGENT_DIR = path.join(__dirname, '../../');
14
+
15
+ const NR_LIB = '/newrelic/lib';
16
+
17
+ const ANONYMOUS_FUNCTION = '<anonymous>';
18
+ const OPEN_PARANTHESIS = '(';
19
+ const COLON = ':';
20
+ const CLOSE_PARANTHESIS = ')';
21
+ const SPACE_CHARACTER = ' ';
22
+ const REPL_MODULE = 'repl';
23
+ const NATIVES_MODULE = 'natives';
24
+ const ASYNC_HOOKS_MODULE = 'async_hooks';
25
+ const JS_EXTENSION = '.js';
26
+ const ACYNC_HOOKS = 'async_hooks.js';
27
+ const RUNINASYNCSCOPE = 'runInAsyncScope';
28
+ const NODE_MODULE = 'node_modules';
29
+ const DOUBLE_DOLLAR = '$$';
30
+ const ATTHERATE = '@';
31
+
32
+ const API = require("../../nr-security-api");
33
+ const logger = API.getLogger();
34
+
35
+ createSkipList();
36
+ const fs = require('fs');
37
+ const cp = require('child_process');
38
+ const requestIp = require('request-ip');
39
+ const URL = require('url')
40
+
41
+ /**
42
+ * Creates a list of loaded internal modules,
43
+ * which is used in sec-trace and by module-tracker.
44
+ *
45
+ * @returns {Array} loadList
46
+ */
47
+ function createSkipList () {
48
+ let loadList = [];
49
+ process.moduleLoadList.forEach(function (loadString) {
50
+ loadList.push(loadString.split(SPACE_CHARACTER).pop());
51
+ });
52
+ loadList = loadList.concat(require(REPL_MODULE)._builtinLibs);
53
+
54
+ loadList = loadList.concat(Object.keys(process.binding(NATIVES_MODULE)));
55
+ for (let i = 0; i < loadList.length; i++) {
56
+ loadList[i] += JS_EXTENSION;
57
+ }
58
+ require('./sec-trace').setLoadList(loadList);
59
+ return loadList;
60
+ }
61
+
62
+
63
+ function getTraceObject (shim) {
64
+ const trace = stackTraceModule.get();
65
+ const traceLength = 10;
66
+ const stkTrace = [];
67
+ for (let i = 0; i < trace.length && stkTrace.length < traceLength; i++) {
68
+ const funcName = trace[i].getFunctionName();
69
+ const fileName = trace[i].getFileName();
70
+ const lineNumber = trace[i].getLineNumber();
71
+
72
+ if (fileName && !fileName.includes(AGENT_DIR) && !fileName.includes(NR_LIB)) {
73
+ const functionName = funcName || ANONYMOUS_FUNCTION;
74
+ const resTrace = functionName + OPEN_PARANTHESIS + fileName + COLON + lineNumber + CLOSE_PARANTHESIS;
75
+ stkTrace.push(resTrace);
76
+ }
77
+ }
78
+ const request = requestManager.getRequest(shim);
79
+ const key = request.method + ATTHERATE + request.uri;
80
+ const routeFile = routeManager.getRoute(key);
81
+ if(routeFile){
82
+ stkTrace.push(routeFile);
83
+ }
84
+ const sourceDetails = secTrace.getSourceDetailsFromTrace(trace,__filename, stkTrace);
85
+ const traceObject = {
86
+ sourceDetails:sourceDetails,
87
+ stacktrace: stkTrace
88
+ }
89
+ return traceObject;
90
+ }
91
+
92
+ function getTraceObjectFallback (request) {
93
+ const trace = stackTraceModule.get();
94
+ const traceLength = 10;
95
+ const stkTrace = [];
96
+ for (let i = 0; i < trace.length && stkTrace.length < traceLength; i++) {
97
+ const funcName = trace[i].getFunctionName();
98
+ const fileName = trace[i].getFileName();
99
+ const lineNumber = trace[i].getLineNumber();
100
+
101
+ if (fileName && !fileName.includes(AGENT_DIR) && !fileName.includes(NR_LIB)) {
102
+ const functionName = funcName || ANONYMOUS_FUNCTION;
103
+ const resTrace = functionName + OPEN_PARANTHESIS + fileName + COLON + lineNumber + CLOSE_PARANTHESIS;
104
+ stkTrace.push(resTrace);
105
+ }
106
+ }
107
+ const key = request.method + ATTHERATE + request.uri;
108
+ const routeFile = routeManager.getRoute(key);
109
+ if(routeFile){
110
+ stkTrace.push(routeFile);
111
+ }
112
+ const sourceDetails = secTrace.getSourceDetailsFromTrace(trace,__filename, stkTrace);
113
+ const traceObject = {
114
+ sourceDetails:sourceDetails,
115
+ stacktrace: stkTrace
116
+ }
117
+ return traceObject;
118
+ }
119
+
120
+
121
+ function traceElementForRoute () {
122
+ const stkTrace = [];
123
+ const trace = stackTraceModule.get();
124
+ let methodName = null;
125
+
126
+ for (let i = 0; i < trace.length - 1; i++) {
127
+ const funcName = trace[i].getFunctionName();
128
+ const fileName = trace[i].getFileName();
129
+ const lineNumber = trace[i].getLineNumber();
130
+ if(i>0){
131
+ methodName = trace[i - 1].getMethodName();
132
+ }
133
+
134
+ if (fileName && !fileName.includes(AGENT_DIR) && fileName !== ACYNC_HOOKS && funcName !== RUNINASYNCSCOPE && !fileName.includes(NODE_MODULE)) {
135
+ const functionName = methodName || funcName || ANONYMOUS_FUNCTION;
136
+ const resTrace = functionName + OPEN_PARANTHESIS + fileName + COLON + lineNumber + CLOSE_PARANTHESIS + DOUBLE_DOLLAR + methodName;
137
+ stkTrace.push(resTrace);
138
+ }
139
+ }
140
+ return stkTrace;
141
+ }
142
+
143
+ function getExecutionId(){
144
+ return async_hooks.executionAsyncId();
145
+ }
146
+
147
+ function createPathIfNotExist (dir) {
148
+ try {
149
+ if (!fs.existsSync(dir)) {
150
+ fs.mkdirSync(dir, 777, { recursive: true });
151
+ logger.info(dir + ' Created');
152
+ fs.chmodSync(dir, 0o777);
153
+ } else {
154
+ fs.chmodSync(dir, 0o777);
155
+ logger.debug(dir + ' Already Exists');
156
+ }
157
+ } catch (error) {
158
+ logger.debug(dir + ' Not Created', error);
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Utility function to add request data in a Map
164
+ * @param {*} shim
165
+ * @param {*} request
166
+ */
167
+ function addRequestData(shim, request) {
168
+ try {
169
+ const data = Object.assign({});
170
+ const segment = shim.getActiveSegment();
171
+ if (segment && segment.transaction) {
172
+ data.body = null;
173
+ data.headers = request.headers;
174
+ data.url = request.url;
175
+ data.method = request.method;
176
+ data.httpVersion = request.httpVersion;
177
+ data.serverPort = segment.transaction.port;
178
+ data.contextPath = '/';
179
+ const queryObject = URL.parse(request.url, true).query;
180
+ data.parameterMap = {};
181
+ if (queryObject) {
182
+ Object.keys(queryObject).forEach(function (key) {
183
+ if (queryObject[key]) {
184
+ if (!data.parameterMap[key]) {
185
+ data.parameterMap[key] = new Array(queryObject[key].toString());
186
+ }
187
+ }
188
+ });
189
+ }
190
+ data.clientIP = requestIp.getClientIp(request);
191
+ const transactionId = segment.transaction.id;
192
+ const storedRequest = requestManager.getRequestFromId(transactionId);
193
+ if (storedRequest && storedRequest.uri) {
194
+ data.uri = storedRequest.uri;
195
+ data.parameterMap = storedRequest.parameterMap;
196
+ }
197
+ requestManager.setRequest(transactionId, data);
198
+ }
199
+ } catch (error) {
200
+ logger.debug("Error while preparing incoming request:", error);
201
+ }
202
+ }
203
+
204
+
205
+ module.exports = {
206
+ getTraceObject,
207
+ traceElementForRoute,
208
+ getExecutionId,
209
+ createPathIfNotExist,
210
+ getTraceObjectFallback,
211
+ addRequestData
212
+ }
@@ -0,0 +1,34 @@
1
+ /*
2
+ * Copyright 2023 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ /**
7
+ * Method to create securityMetadata object
8
+ * @param {*} request
9
+ * @param {*} interceptedArgs
10
+ * @param {*} traceObject
11
+ * @param {*} executionId
12
+ * @param {*} eventType
13
+ * @param {*} eventCategory
14
+ * @returns
15
+ */
16
+ function getSecurityMetaData(request, interceptedArgs, traceObject, executionId, eventType, eventCategory) {
17
+ const securityMetadata = {};
18
+ const httpRequest = Object.assign({},request);
19
+ if(httpRequest.tempFiles){
20
+ delete httpRequest.tempFiles;
21
+ }
22
+ securityMetadata.request = httpRequest
23
+ securityMetadata.interceptedArgs = interceptedArgs;
24
+ securityMetadata.traceObject = traceObject
25
+ securityMetadata.executionId = executionId
26
+ securityMetadata.eventType = eventType
27
+ securityMetadata.eventCategory = eventCategory
28
+ return securityMetadata;
29
+
30
+ }
31
+
32
+ module.exports = {
33
+ getSecurityMetaData
34
+ }