@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.
- package/CHANGELOG.md +0 -0
- package/CONTRIBUTING.md +23 -0
- package/LICENSE +43 -0
- package/README.md +98 -0
- package/THIRD_PARTY_NOTICES.md +2909 -0
- package/index.js +24 -0
- package/lib/instrumentation-security/core/constants.js +66 -0
- package/lib/instrumentation-security/core/event-constants.js +49 -0
- package/lib/instrumentation-security/core/request-manager.js +73 -0
- package/lib/instrumentation-security/core/route-manager.js +30 -0
- package/lib/instrumentation-security/core/sec-trace.js +134 -0
- package/lib/instrumentation-security/core/sec-utils.js +212 -0
- package/lib/instrumentation-security/core/security-metadata.js +34 -0
- package/lib/instrumentation-security/core/stack-trace.js +156 -0
- package/lib/instrumentation-security/hooks/director/nr-director.js +98 -0
- package/lib/instrumentation-security/hooks/express/nr-express.js +106 -0
- package/lib/instrumentation-security/hooks/fastify/nr-fastify.js +155 -0
- package/lib/instrumentation-security/hooks/fs/nr-fs.js +391 -0
- package/lib/instrumentation-security/hooks/hapi/nr-hapi.js +131 -0
- package/lib/instrumentation-security/hooks/http/nr-http.js +461 -0
- package/lib/instrumentation-security/hooks/koa/@koa/nr-@koa-router.js +110 -0
- package/lib/instrumentation-security/hooks/ldap/nr-ldap.js +81 -0
- package/lib/instrumentation-security/hooks/mongodb/common.js +239 -0
- package/lib/instrumentation-security/hooks/mongodb/constants.js +91 -0
- package/lib/instrumentation-security/hooks/mongodb/nr-mongodb.js +49 -0
- package/lib/instrumentation-security/hooks/mongodb/v2-mongo.js +91 -0
- package/lib/instrumentation-security/hooks/mongodb/v3-mongo.js +36 -0
- package/lib/instrumentation-security/hooks/mongodb/v4-mongo.js +17 -0
- package/lib/instrumentation-security/hooks/mysql/nr-mysql.js +232 -0
- package/lib/instrumentation-security/hooks/native/nr-childProcess.js +131 -0
- package/lib/instrumentation-security/hooks/postgres/nr-postgres.js +131 -0
- package/lib/instrumentation-security/hooks/require/nr-require.js +93 -0
- package/lib/instrumentation-security/hooks/restify/nr-restify.js +104 -0
- package/lib/instrumentation-security/hooks/xpath/nr-xpath.js +91 -0
- package/lib/instrumentation-security/index.js +171 -0
- package/lib/nr-security-agent/index.js +170 -0
- package/lib/nr-security-agent/lib/core/Auth-headers.js +58 -0
- package/lib/nr-security-agent/lib/core/ContainerProperties.js +42 -0
- package/lib/nr-security-agent/lib/core/ECSProperties.js +34 -0
- package/lib/nr-security-agent/lib/core/FuzzFailEvent.js +27 -0
- package/lib/nr-security-agent/lib/core/LinkingMetadata.js +21 -0
- package/lib/nr-security-agent/lib/core/LogMessage.js +47 -0
- package/lib/nr-security-agent/lib/core/PodProperties.js +36 -0
- package/lib/nr-security-agent/lib/core/Policy.js +105 -0
- package/lib/nr-security-agent/lib/core/agent-status.js +56 -0
- package/lib/nr-security-agent/lib/core/agent.js +146 -0
- package/lib/nr-security-agent/lib/core/applicationinfo.js +634 -0
- package/lib/nr-security-agent/lib/core/commonUtils.js +411 -0
- package/lib/nr-security-agent/lib/core/connections/aws-lambda-client.js +55 -0
- package/lib/nr-security-agent/lib/core/connections/restclient.js +20 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/index.js +25 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/collecotor-policy-error-handler.js +18 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/collector-policy-handler.js +20 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/fuzz-request-handler.js +171 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/index.js +47 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/no-op-handler.js +12 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/startup-handshake-handler.js +27 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/unsupported-agent-handler.js +18 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/ws-reconnect.js +14 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/websocket.js +443 -0
- package/lib/nr-security-agent/lib/core/event.js +186 -0
- package/lib/nr-security-agent/lib/core/health-check.js +159 -0
- package/lib/nr-security-agent/lib/core/json-file-handler.js +66 -0
- package/lib/nr-security-agent/lib/core/jsonValidator.js +149 -0
- package/lib/nr-security-agent/lib/core/lambda-delegated-task-service.js +90 -0
- package/lib/nr-security-agent/lib/core/logging.js +176 -0
- package/lib/nr-security-agent/lib/core/sec-agent-constants.js +173 -0
- package/lib/nr-security-agent/lib/core/sec-util.js +166 -0
- package/lib/nr-security-agent/lib/core/sha-size-util.js +338 -0
- package/lib/nr-security-agent/lib/core/sha_worker.js +24 -0
- package/lib/nr-security-agent/lib/core/startup-config.js +29 -0
- package/lib/nr-security-agent/lib/core/statusUtils.js +157 -0
- package/lib/nr-security-agent/lib/core/timeunit.js +44 -0
- package/lib/nr-security-agent/lib/core/websocket-client.js +335 -0
- package/lib/nr-security-agent/lib/core/worker-entities.js +82 -0
- package/lib/nr-security-agent/lib/core/worker.js +148 -0
- package/lib/nr-security-agent/lib/core/xss-utils.js +297 -0
- package/lib/nr-security-agent/lib/models/lambda-delegated-task/constants.js +12 -0
- package/lib/nr-security-agent/lib/models/lambda-delegated-task/index.js +15 -0
- package/lib/nr-security-agent/lib/models/lambda-delegated-task/lambda-delegated-sha-calculation.js +37 -0
- package/lib/nr-security-agent/lib/models/lambda-delegated-task/lambda-delegated-task-base.js +50 -0
- package/lib/nr-security-agent/lib/models/lambda-delegated-task/lambda-delegated-task-type.js +17 -0
- package/lib/nr-security-agent/resources/cert.pem +31 -0
- package/lib/nr-security-agent/resources/config.js +19 -0
- package/lib/nr-security-agent/resources/default-policy.yaml +36 -0
- package/lib/nr-security-api/index.js +111 -0
- 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
|
+
}
|