@newrelic/security-agent 0.1.2 → 0.2.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.
- package/CHANGELOG.md +15 -0
- package/THIRD_PARTY_NOTICES.md +17 -28
- package/lib/instrumentation-security/core/constants.js +0 -1
- package/lib/instrumentation-security/hooks/fs/nr-fs.js +6 -5
- package/lib/instrumentation-security/hooks/http/nr-http.js +2 -2
- package/lib/instrumentation-security/hooks/mysql/nr-mysql.js +16 -0
- package/lib/instrumentation-security/hooks/native/nr-childProcess.js +1 -1
- package/lib/instrumentation-security/hooks/require/nr-require.js +12 -5
- package/lib/nr-security-agent/lib/core/Auth-headers.js +1 -0
- package/lib/nr-security-agent/lib/core/applicationinfo.js +1 -1
- package/lib/nr-security-agent/lib/core/commonUtils.js +12 -12
- package/lib/nr-security-agent/lib/core/connections/websocket/index.js +0 -6
- package/lib/nr-security-agent/lib/core/connections/websocket/response/IASTUtils.js +50 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/collector-policy-handler.js +4 -1
- package/lib/nr-security-agent/lib/core/connections/websocket/response/fuzz-request-handler.js +90 -31
- package/lib/nr-security-agent/lib/core/connections/websocket/response/iast-cool-down.js +15 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/iast-record-deletion.js +19 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/index.js +17 -5
- package/lib/nr-security-agent/lib/core/connections/websocket/websocket.js +23 -61
- package/lib/nr-security-agent/lib/core/logging.js +89 -71
- package/lib/nr-security-agent/lib/core/sec-agent-constants.js +3 -2
- package/lib/nr-security-agent/lib/core/statusUtils.js +1 -1
- package/lib/nr-security-agent/lib/core/websocket-client.js +5 -168
- package/lib/nr-security-agent/lib/core/xss-utils.js +2 -3
- package/lib/nr-security-agent/resources/config.js +2 -2
- package/package.json +11 -11
- package/lib/nr-security-agent/lib/core/worker-entities.js +0 -82
- package/lib/nr-security-agent/lib/core/worker.js +0 -148
|
@@ -16,18 +16,24 @@ const LOG_PATTERN_OBJ = {
|
|
|
16
16
|
type: 'pattern',
|
|
17
17
|
pattern: '%[%d[%p][%c][%h][%z]%] %m'
|
|
18
18
|
};
|
|
19
|
-
const { LOG_DIR } = require('./sec-agent-constants');
|
|
19
|
+
const { LOG_DIR, CSEC_HOME } = require('./sec-agent-constants');
|
|
20
20
|
let logger;
|
|
21
21
|
const API = require('../../../nr-security-api');
|
|
22
22
|
const NRAgent = API.getNRAgent();
|
|
23
23
|
|
|
24
24
|
const logFileName = `${LOG_DIR}node-security-collector.log`;
|
|
25
25
|
const initLogFileName = `${LOG_DIR}node-security-collector-init.log`;
|
|
26
|
+
let isLoggerOk = true;
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
|
|
29
|
+
function createLogPathIfNotExist(dir) {
|
|
28
30
|
try {
|
|
29
31
|
if (!fs.existsSync(dir)) {
|
|
30
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
32
|
+
fs.mkdirSync(dir, 777, { recursive: true });
|
|
33
|
+
fs.chmodSync(dir, 0o777);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
fs.chmodSync(dir, 0o777);
|
|
31
37
|
}
|
|
32
38
|
} catch (error) {
|
|
33
39
|
}
|
|
@@ -37,90 +43,103 @@ function createLogPathIfNotExist (dir) {
|
|
|
37
43
|
* Initializes the logger appenders.
|
|
38
44
|
* @param {v4uuid} applicationUUID
|
|
39
45
|
*/
|
|
40
|
-
function initialize
|
|
41
|
-
const appenders = {};
|
|
42
|
-
appenders.NR_CSEC = {
|
|
43
|
-
type: 'file',
|
|
44
|
-
compress: false,
|
|
45
|
-
layout: LOG_PATTERN_OBJ
|
|
46
|
-
};
|
|
47
|
-
appenders.NR_CSEC_INIT = {
|
|
48
|
-
type: 'file',
|
|
49
|
-
compress: false,
|
|
50
|
-
layout: LOG_PATTERN_OBJ
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
const logLevel = NRAgent && NRAgent.config && NRAgent.config.logging.enabled ? NRAgent.config.logging.level : 'info';
|
|
54
|
-
|
|
46
|
+
function initialize(applicationUUID) {
|
|
55
47
|
try {
|
|
56
|
-
|
|
57
|
-
|
|
48
|
+
const logLevel = NRAgent && NRAgent.config && NRAgent.config.logging.enabled ? NRAgent.config.logging.level : 'info';
|
|
49
|
+
const apmLogFilePath = NRAgent && NRAgent.config && NRAgent.config.logging.enabled ? NRAgent.config.logging.filepath : '';
|
|
50
|
+
let appenderType = 'file';
|
|
51
|
+
|
|
52
|
+
if (apmLogFilePath === 'stdout') {
|
|
53
|
+
appenderType = 'stdout';
|
|
58
54
|
}
|
|
59
|
-
} catch (error) {
|
|
60
|
-
}
|
|
61
55
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
Object.assign(appenders.NR_CSEC_INIT, {
|
|
69
|
-
filename: initLogFileName,
|
|
70
|
-
maxLogSize: LOG_FILE_SIZE,
|
|
71
|
-
backups: 0
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
const categories = {
|
|
75
|
-
default: {
|
|
76
|
-
appenders: [
|
|
77
|
-
'NR_CSEC'
|
|
78
|
-
],
|
|
79
|
-
level: logLevel
|
|
80
|
-
},
|
|
81
|
-
NR_CSEC_INIT: {
|
|
82
|
-
appenders: [
|
|
83
|
-
'NR_CSEC_INIT',
|
|
84
|
-
'NR_CSEC'
|
|
85
|
-
],
|
|
86
|
-
level: logLevel
|
|
87
|
-
},
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
if (env === 'dev' || env === 'trace') {
|
|
91
|
-
appenders.STDOUT = {
|
|
92
|
-
type: 'stdout',
|
|
56
|
+
const appenders = {};
|
|
57
|
+
appenders.NR_CSEC = {
|
|
58
|
+
type: appenderType,
|
|
59
|
+
compress: false,
|
|
93
60
|
layout: LOG_PATTERN_OBJ
|
|
94
61
|
};
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
62
|
+
appenders.NR_CSEC_INIT = {
|
|
63
|
+
type: appenderType,
|
|
64
|
+
compress: false,
|
|
65
|
+
layout: LOG_PATTERN_OBJ
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
createLogPathIfNotExist(CSEC_HOME);
|
|
70
|
+
createLogPathIfNotExist(LOG_DIR);
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
Object.assign(appenders.NR_CSEC, {
|
|
74
|
+
filename: logFileName,
|
|
75
|
+
maxLogSize: LOG_FILE_SIZE,
|
|
76
|
+
backups: 0
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
Object.assign(appenders.NR_CSEC_INIT, {
|
|
80
|
+
filename: initLogFileName,
|
|
81
|
+
maxLogSize: LOG_FILE_SIZE,
|
|
82
|
+
backups: 0
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const categories = {
|
|
86
|
+
default: {
|
|
87
|
+
appenders: [
|
|
88
|
+
'NR_CSEC'
|
|
89
|
+
],
|
|
90
|
+
level: logLevel
|
|
91
|
+
},
|
|
92
|
+
NR_CSEC_INIT: {
|
|
93
|
+
appenders: [
|
|
94
|
+
'NR_CSEC_INIT',
|
|
95
|
+
],
|
|
96
|
+
level: logLevel
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
if (apmLogFilePath !== 'stdout') {
|
|
101
|
+
categories.NR_CSEC_INIT.appenders.push('NR_CSEC')
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
if (env === 'dev' || env === 'trace') {
|
|
106
|
+
appenders.STDOUT = {
|
|
107
|
+
type: 'stdout',
|
|
108
|
+
layout: LOG_PATTERN_OBJ
|
|
109
|
+
};
|
|
110
|
+
categories.default.appenders.push('STDOUT');
|
|
111
|
+
categories.NR_CSEC_INIT.appenders.push('STDOUT');
|
|
112
|
+
}
|
|
98
113
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
114
|
+
log4js.configure({
|
|
115
|
+
appenders: appenders,
|
|
116
|
+
categories: categories,
|
|
117
|
+
disableClustering: true
|
|
118
|
+
});
|
|
119
|
+
} catch (error) {
|
|
120
|
+
console.error("Error while logging into file. Fallback to stdout.", error.message);
|
|
121
|
+
isLoggerOk = false;
|
|
122
|
+
}
|
|
105
123
|
}
|
|
106
124
|
|
|
107
125
|
/**
|
|
108
126
|
* sets the logging level of current instance.
|
|
109
127
|
* @param {String} level
|
|
110
128
|
*/
|
|
111
|
-
function setLevel
|
|
129
|
+
function setLevel(level = INFO) {
|
|
112
130
|
level = level.trim();
|
|
113
131
|
if (logger) {
|
|
114
132
|
logger.level = level;
|
|
115
|
-
}
|
|
116
|
-
|
|
133
|
+
}
|
|
134
|
+
if (!isLoggerOk) {
|
|
135
|
+
logger.level = INFO;
|
|
117
136
|
}
|
|
118
137
|
}
|
|
119
138
|
|
|
120
139
|
/**
|
|
121
140
|
* get the logging level of current instance.
|
|
122
141
|
*/
|
|
123
|
-
function getLevel
|
|
142
|
+
function getLevel() {
|
|
124
143
|
if (logger) {
|
|
125
144
|
return logger.level;
|
|
126
145
|
} else {
|
|
@@ -134,7 +153,7 @@ function getLevel () {
|
|
|
134
153
|
* already made.
|
|
135
154
|
* @param {v4uuid} applicationUUID
|
|
136
155
|
*/
|
|
137
|
-
function getLogger
|
|
156
|
+
function getLogger(applicationUUID = process.env.applicationUUID) {
|
|
138
157
|
if (logger) {
|
|
139
158
|
return logger;
|
|
140
159
|
}
|
|
@@ -146,9 +165,8 @@ function getLogger (applicationUUID = process.env.applicationUUID) {
|
|
|
146
165
|
fs.chmodSync(`${logFileName}`, 0o777);
|
|
147
166
|
fs.chmodSync(`${initLogFileName}`, 0o777);
|
|
148
167
|
} catch (error) {
|
|
149
|
-
logger.error("Error while setting up permissions on log files", error);
|
|
150
168
|
}
|
|
151
|
-
initLogger.info("[STEP-2] => Generating unique identifier:",applicationUUID
|
|
169
|
+
initLogger.info("[STEP-2] => Generating unique identifier:", applicationUUID)
|
|
152
170
|
if (NRAgent) {
|
|
153
171
|
setLevel(NRAgent.config.logging.level);
|
|
154
172
|
}
|
|
@@ -159,14 +177,14 @@ function getLogger (applicationUUID = process.env.applicationUUID) {
|
|
|
159
177
|
}
|
|
160
178
|
}
|
|
161
179
|
|
|
162
|
-
function reCreateLogger
|
|
180
|
+
function reCreateLogger(applicationUUID) {
|
|
163
181
|
initialize(applicationUUID);
|
|
164
182
|
logger = log4js.getLogger('NR_CSEC');
|
|
165
183
|
setLevel(logger.level);
|
|
166
184
|
updateModuleLoggers(logger);
|
|
167
185
|
}
|
|
168
186
|
|
|
169
|
-
function getInitLogger
|
|
187
|
+
function getInitLogger() {
|
|
170
188
|
const initLogger = log4js.getLogger('NR_CSEC_INIT');
|
|
171
189
|
return initLogger;
|
|
172
190
|
}
|
|
@@ -49,7 +49,9 @@ module.exports = {
|
|
|
49
49
|
COLLECTOR_CONFIG: 100,
|
|
50
50
|
BLOCKING: 101,
|
|
51
51
|
POLICY_ERROR: 102,
|
|
52
|
-
OBEY_WS_RECONNECT:12
|
|
52
|
+
OBEY_WS_RECONNECT:12,
|
|
53
|
+
ENTER_IAST_COOLDOWN:13,
|
|
54
|
+
IAST_RECORD_DELETE_CONFIRMATION:14
|
|
53
55
|
|
|
54
56
|
},
|
|
55
57
|
JSON_NAME: {
|
|
@@ -74,7 +76,6 @@ module.exports = {
|
|
|
74
76
|
(process.env[AWS_EXECUTION_ENV_VAR] || '').match(AWS_LAMBDA_NODE_EXEC_ENV_IDENTIFIER)
|
|
75
77
|
),
|
|
76
78
|
LAMBDA_RUNTIME_DIR_VAR: 'LAMBDA_RUNTIME_DIR',
|
|
77
|
-
CSEC_LAST_FUZZ_REQUEST_TIME: 'CSEC_LAST_FUZZ_REQUEST_TIME',
|
|
78
79
|
NR_CSEC_FUZZ_REQUEST_ID: 'nr-csec-fuzz-request-id',
|
|
79
80
|
EMPTY_APPLICATION_UUID: '--0--',
|
|
80
81
|
QUESTIONMARK: '?',
|
|
@@ -95,7 +95,7 @@ function writeSnapshot() {
|
|
|
95
95
|
commonUtils.removeOlderSnapshots();
|
|
96
96
|
fs.writeFile(statusFile, snapshot, { mode: 0o777 }, function (err) {
|
|
97
97
|
if (err) {
|
|
98
|
-
logger.
|
|
98
|
+
logger.debug(err.message);
|
|
99
99
|
} else {
|
|
100
100
|
logger.info('Snapshot updated to file: %s', statusFile);
|
|
101
101
|
fs.chmod(statusFile, 0o777, (err) => {
|
|
@@ -4,8 +4,6 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
|
-
const path = require('path');
|
|
8
|
-
const RingBuffer = require('ringbufferjs');
|
|
9
7
|
const LOG_MESSAGES = require('./sec-agent-constants').LOG_MESSAGES;
|
|
10
8
|
|
|
11
9
|
const { Agent } = require('./agent');
|
|
@@ -14,31 +12,21 @@ const hc = require('./health-check');
|
|
|
14
12
|
const applicationInfo = require('./applicationinfo').getInstance();
|
|
15
13
|
const logger = require('./logging').getLogger(applicationInfo.applicationUUID);
|
|
16
14
|
const initLogger = require('./logging').getInitLogger();
|
|
17
|
-
const { WorkerMessage, WORKER_STATUS } = require('./worker-entities');
|
|
18
15
|
const commonUtils = require('./commonUtils');
|
|
19
16
|
const API = require('../../../nr-security-api');
|
|
20
17
|
const NRAgent = API.getNRAgent();
|
|
21
18
|
const {
|
|
22
19
|
SecWebSocket,
|
|
23
20
|
setWebSocketConn,
|
|
24
|
-
aquireWebSocket,
|
|
25
21
|
ResponseHandler: {
|
|
26
|
-
handle: handleServerResponse,
|
|
27
22
|
setLogger: setResponseHandlerLogger
|
|
28
23
|
}
|
|
29
24
|
} = require('./connections/websocket');
|
|
30
25
|
const { HC_INTERVAL_MS } = require('../../resources/config');
|
|
31
|
-
const {
|
|
26
|
+
const { LOG_DIR } = require('./sec-agent-constants');
|
|
32
27
|
const statusUtils = require('./statusUtils');
|
|
33
28
|
const njsAgentConstants = require('./sec-agent-constants');
|
|
34
29
|
|
|
35
|
-
const MAX_BUSY_WAIT_TIME = 5000; // ms
|
|
36
|
-
const workerSupported = commonUtils.hasWorker();;
|
|
37
|
-
const filePath = path.join(__dirname, 'worker.js');
|
|
38
|
-
const localQueue = new RingBuffer(1000);
|
|
39
|
-
|
|
40
|
-
let busy = false;
|
|
41
|
-
let wsWorker;
|
|
42
30
|
let wsInstance;
|
|
43
31
|
let dispatcher;
|
|
44
32
|
|
|
@@ -65,11 +53,8 @@ const initialize = function () {
|
|
|
65
53
|
|
|
66
54
|
setResponseHandlerLogger(logger);
|
|
67
55
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
} else {
|
|
71
|
-
initializeInMainThread();
|
|
72
|
-
}
|
|
56
|
+
initializeInMainThread();
|
|
57
|
+
|
|
73
58
|
// we'll dispatch the application info if it is updated
|
|
74
59
|
Agent.eventEmitter.on(Agent.EVENTS.APPLICATION_INFO_UPDATE_EVENT, (applicationInfo) => {
|
|
75
60
|
if (!NRAgent || (NRAgent && applicationInfo.entityGuid)) {
|
|
@@ -78,12 +63,7 @@ const initialize = function () {
|
|
|
78
63
|
});
|
|
79
64
|
Agent.eventEmitter.on(Agent.EVENTS.RECONNECT_WS_EVENT, () => {
|
|
80
65
|
setWebSocketConn();
|
|
81
|
-
|
|
82
|
-
const reConnectMsg = new WorkerMessage(WorkerMessage.TYPE.RECONNECT, {});
|
|
83
|
-
wsWorker.postMessage(reConnectMsg);
|
|
84
|
-
} else {
|
|
85
|
-
wsInstance.reconnect();
|
|
86
|
-
}
|
|
66
|
+
wsInstance.reconnect();
|
|
87
67
|
});
|
|
88
68
|
|
|
89
69
|
setTimeout(() => {
|
|
@@ -106,102 +86,11 @@ function initializeInMainThread() {
|
|
|
106
86
|
dispatcher = function dispatcher(message) {
|
|
107
87
|
wsInstance.dispatch(message);
|
|
108
88
|
};
|
|
109
|
-
|
|
110
|
-
// Setup the event listeners
|
|
111
|
-
wsInstance.event.on(SecWebSocket.Events.BUSY, function () {
|
|
112
|
-
busy = true;
|
|
113
|
-
});
|
|
114
|
-
wsInstance.event.on(SecWebSocket.Events.INACTIVE, function () {
|
|
115
|
-
busy = false;
|
|
116
|
-
});
|
|
117
89
|
} else {
|
|
118
90
|
return wsInstance;
|
|
119
91
|
}
|
|
120
92
|
}
|
|
121
93
|
|
|
122
|
-
/**
|
|
123
|
-
* This initiates the ws in worker thread
|
|
124
|
-
*/
|
|
125
|
-
function initiateInWorkerThread() {
|
|
126
|
-
if (workerSupported) {
|
|
127
|
-
process.env.WS_WORKER_STATUS = WORKER_STATUS.INITIALIZING;
|
|
128
|
-
try {
|
|
129
|
-
setWebSocketConn();
|
|
130
|
-
const { Worker, SHARE_ENV } = require('worker_threads');
|
|
131
|
-
wsWorker = new Worker(filePath, {
|
|
132
|
-
workerData: {
|
|
133
|
-
applicationInfo
|
|
134
|
-
},
|
|
135
|
-
env: SHARE_ENV
|
|
136
|
-
});
|
|
137
|
-
wsWorker.on('message', handleWorkerMessage);
|
|
138
|
-
wsWorker.on('error', (err) => {
|
|
139
|
-
logger.error('Exception in web socket worker:', err.message);
|
|
140
|
-
wsWorker = new Worker(filePath, {
|
|
141
|
-
workerData: {
|
|
142
|
-
applicationInfo
|
|
143
|
-
}, env: SHARE_ENV
|
|
144
|
-
});
|
|
145
|
-
});
|
|
146
|
-
dispatcher = function dispatcher(message) {
|
|
147
|
-
if (process.env.WS_WORKER_STATUS !== WORKER_STATUS.RUNNING) {
|
|
148
|
-
localQueue.enq(message);
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
// websocket is aquired here and then
|
|
152
|
-
// released in worker thread when the
|
|
153
|
-
// handoff to websocket is confirmed
|
|
154
|
-
aquireWebSocket();
|
|
155
|
-
const msg = new WorkerMessage(WorkerMessage.TYPE.MESSAGE, message);
|
|
156
|
-
wsWorker.postMessage(msg);
|
|
157
|
-
};
|
|
158
|
-
logger.info(LOG_MESSAGES.NODE_VERSION_MSG_WORKER, process.version);
|
|
159
|
-
} catch (error) {
|
|
160
|
-
logger.debug('error is:', error);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* This handles any messages received from worker
|
|
167
|
-
* if websocket worker is initialized
|
|
168
|
-
*
|
|
169
|
-
* @param {JSON} json
|
|
170
|
-
*/
|
|
171
|
-
function handleWorkerMessage(json) {
|
|
172
|
-
const msg = WorkerMessage.parseFromObject(json);
|
|
173
|
-
switch (msg.type) {
|
|
174
|
-
case WorkerMessage.TYPE.MESSAGE: {
|
|
175
|
-
logger.debug(LOG_MESSAGES.MSG_FROM_WORKKER, msg.getPayload());
|
|
176
|
-
handleServerResponse(msg.getPayload());
|
|
177
|
-
break;
|
|
178
|
-
}
|
|
179
|
-
case WorkerMessage.TYPE.FLUSH: {
|
|
180
|
-
const { status } = msg.getPayload();
|
|
181
|
-
if (status === 'flushed') {
|
|
182
|
-
logger.debug('Message from worker thread: Flush Completed');
|
|
183
|
-
}
|
|
184
|
-
break;
|
|
185
|
-
}
|
|
186
|
-
case WorkerMessage.TYPE.IC_READY_FOR_EVENTS: {
|
|
187
|
-
break;
|
|
188
|
-
}
|
|
189
|
-
case WorkerMessage.TYPE.BUSY: {
|
|
190
|
-
busy = true;
|
|
191
|
-
break;
|
|
192
|
-
}
|
|
193
|
-
case WorkerMessage.TYPE.INACTIVE: {
|
|
194
|
-
busy = false;
|
|
195
|
-
break;
|
|
196
|
-
}
|
|
197
|
-
case WorkerMessage.TYPE.ERROR: {
|
|
198
|
-
statusUtils.addErrortoBuffer(msg.getPayload());
|
|
199
|
-
break;
|
|
200
|
-
}
|
|
201
|
-
default:
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
94
|
/**
|
|
206
95
|
* Sends Agent HelthCheck to Validator.
|
|
207
96
|
*/
|
|
@@ -267,66 +156,14 @@ function sendEvent(event, callback = DEFAULT_EVENT_SEND_CB) {
|
|
|
267
156
|
callback();
|
|
268
157
|
};
|
|
269
158
|
|
|
270
|
-
/**
|
|
271
|
-
* Flushes local queue to the worker
|
|
272
|
-
*/
|
|
273
|
-
function flushLocalQueue() {
|
|
274
|
-
if (!workerSupported) return;
|
|
275
|
-
|
|
276
|
-
while (!localQueue.isEmpty()) {
|
|
277
|
-
dispatcher(localQueue.deq());
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Waits for websocket to get idel before
|
|
283
|
-
* exiting the lambda function
|
|
284
|
-
* @param {Number} startTime
|
|
285
|
-
*/
|
|
286
|
-
function busyWaitOnWorkerThread(startTime = Date.now()) {
|
|
287
|
-
if (!workerSupported) return;
|
|
288
|
-
|
|
289
|
-
const workerInitiatedOnWait = process.env.WS_WORKER_STATUS === WORKER_STATUS.RUNNING;
|
|
290
|
-
const enableWait = !IS_LAMBDA_ENV || process.env[LAMBDA_ENABLE_RESPONSE_BLOCKING] === 'true';
|
|
291
|
-
|
|
292
|
-
let flushed = false;
|
|
293
|
-
let wait = (
|
|
294
|
-
process.env.CSEC_WS_STATE === SecWebSocket.States.CONNECTING ||
|
|
295
|
-
(
|
|
296
|
-
enableWait &&
|
|
297
|
-
process.env.CSEC_WS_STATE === SecWebSocket.States.BUSY
|
|
298
|
-
)
|
|
299
|
-
) && (startTime + MAX_BUSY_WAIT_TIME > Date.now());
|
|
300
|
-
while (wait) {
|
|
301
|
-
wait = (
|
|
302
|
-
process.env.CSEC_WS_STATE === SecWebSocket.States.CONNECTING ||
|
|
303
|
-
(
|
|
304
|
-
enableWait &&
|
|
305
|
-
process.env.CSEC_WS_STATE === SecWebSocket.States.BUSY
|
|
306
|
-
)
|
|
307
|
-
) && (startTime + MAX_BUSY_WAIT_TIME > Date.now());
|
|
308
|
-
|
|
309
|
-
if (!flushed && !workerInitiatedOnWait && process.env.WS_WORKER_STATUS === WORKER_STATUS.RUNNING) {
|
|
310
|
-
flushed = true;
|
|
311
|
-
flushLocalQueue();
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
159
|
|
|
316
160
|
function obeyReconnect() {
|
|
317
|
-
|
|
318
|
-
const reConnectMsg = new WorkerMessage(WorkerMessage.TYPE.OBEY_RECONNECT, {});
|
|
319
|
-
wsWorker.postMessage(reConnectMsg);
|
|
320
|
-
} else {
|
|
321
|
-
wsInstance.obeyReconnect();
|
|
322
|
-
}
|
|
161
|
+
wsInstance.obeyReconnect();
|
|
323
162
|
}
|
|
324
163
|
|
|
325
164
|
module.exports = {
|
|
326
165
|
initialize,
|
|
327
166
|
write: sendEvent,
|
|
328
167
|
dispatcher: getDispatcherAndSendEvent,
|
|
329
|
-
flushLocalQueue,
|
|
330
|
-
busyWaitOnWorkerThread,
|
|
331
168
|
obeyReconnect
|
|
332
169
|
};
|
|
@@ -4,13 +4,12 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
const _ = require('lodash');
|
|
7
|
-
const { AllHtmlEntities } = require('html-entities');
|
|
8
7
|
const decode = require('unescape');
|
|
9
8
|
const querystring = require('querystring');
|
|
10
9
|
|
|
11
10
|
const { Agent } = require('./agent');
|
|
12
11
|
|
|
13
|
-
const
|
|
12
|
+
const htmlEntities = require('html-entities');
|
|
14
13
|
|
|
15
14
|
const tagNameRegex = /<([a-zA-Z_-]+[0-9]*|!--)/gmi;
|
|
16
15
|
const attribRegex = /([^(/\s<'">)]+?)(?:\s*)=\s*(('|")([\s\S]*?)(?:(?=(\\?))\5.)*?\3|.+?(?=\/>|>|\?>|\s|<\/|$))/gmi;
|
|
@@ -222,7 +221,7 @@ function getXSSConstructs (data) {
|
|
|
222
221
|
if (!_.isEmpty(key) && (upperCaseAttribKey.startsWith('ON') || upperCaseAttribKey === 'SRC' || upperCaseAttribKey === 'HREF' ||
|
|
223
222
|
upperCaseAttribKey === 'ACTION' || upperCaseAttribKey === 'FORMACTION' || upperCaseAttribKey === 'SRCDOC' ||
|
|
224
223
|
upperCaseAttribKey === 'DATA' || decode(val).toUpperCase().replace(/\s/g, '').includes('JAVASCRIPT:') ||
|
|
225
|
-
|
|
224
|
+
htmlEntities.decode(val).toUpperCase().replace(/\s/g, '').includes('JAVASCRIPT:'))) {
|
|
226
225
|
isAttackConstruct = true;
|
|
227
226
|
}
|
|
228
227
|
} else {
|
|
@@ -11,8 +11,8 @@ if(process.platform == 'win32'){
|
|
|
11
11
|
AGENT_DIR = path.join(__dirname, "..\\..\\..\\");
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
const
|
|
15
|
-
process.env.applicationUUID = process.env.applicationUUID ||
|
|
14
|
+
const uuid = require('uuid');
|
|
15
|
+
process.env.applicationUUID = process.env.applicationUUID || uuid.v4();
|
|
16
16
|
|
|
17
17
|
module.exports = {
|
|
18
18
|
AGENT_DIR,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@newrelic/security-agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "New Relic Security Agent for Node.js",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"jsonVersion": "1.0.1",
|
|
@@ -37,25 +37,25 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@aws-sdk/client-lambda": "^3.348.0",
|
|
39
39
|
"axios": "0.21.4",
|
|
40
|
-
"check-disk-space": "^3.
|
|
41
|
-
"content-type": "^1.0.
|
|
42
|
-
"fast-safe-stringify": "^2.
|
|
40
|
+
"check-disk-space": "^3.4.0",
|
|
41
|
+
"content-type": "^1.0.5",
|
|
42
|
+
"fast-safe-stringify": "^2.1.1",
|
|
43
43
|
"find-package-json": "^1.2.0",
|
|
44
44
|
"hash.js": "^1.1.7",
|
|
45
|
-
"html-entities": "^
|
|
45
|
+
"html-entities": "^2.3.6",
|
|
46
46
|
"is-invalid-path": "^1.0.2",
|
|
47
47
|
"js-yaml": "^4.1.0",
|
|
48
|
-
"jsonschema": "^1.4.
|
|
48
|
+
"jsonschema": "^1.4.1",
|
|
49
49
|
"lodash": "^4.17.21",
|
|
50
|
-
"log4js": "^6.
|
|
50
|
+
"log4js": "^6.9.1",
|
|
51
51
|
"pretty-bytes": "^5.6.0",
|
|
52
|
-
"request-ip": "^
|
|
52
|
+
"request-ip": "^3.3.0",
|
|
53
53
|
"ringbufferjs": "^2.0.0",
|
|
54
|
-
"semver": "^
|
|
54
|
+
"semver": "^7.5.3",
|
|
55
55
|
"sync-request": "^6.1.0",
|
|
56
56
|
"unescape": "^1.0.1",
|
|
57
57
|
"unescape-js": "^1.1.4",
|
|
58
|
-
"uuid": "^
|
|
58
|
+
"uuid": "^9.0.0",
|
|
59
59
|
"ws": "^7.5.9"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"mongodb-memory-server": "^8.11.2",
|
|
82
82
|
"mongodb2": "npm:mongodb@^2.2.36",
|
|
83
83
|
"mongodb3": "npm:mongodb@^3.7.3",
|
|
84
|
-
"newrelic": "^
|
|
84
|
+
"newrelic": "^10.3.1",
|
|
85
85
|
"request": "^2.88.2",
|
|
86
86
|
"restify": "^11.1.0",
|
|
87
87
|
"sinon": "^15.0.0",
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright 2023 New Relic Corporation. All rights reserved.
|
|
3
|
-
* SPDX-License-Identifier: New Relic Pre-Release
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const MESSAGE = 'MESSAGE';
|
|
7
|
-
const FLUSH = 'FLUSH';
|
|
8
|
-
const BUSY = 'BUSY';
|
|
9
|
-
const INACTIVE = 'INACTIVE';
|
|
10
|
-
const RECONNECT = 'RECONNECT';
|
|
11
|
-
const UPDATE_APPLICATION_INFO = 'UPDATE APPLICATION INFO';
|
|
12
|
-
const IC_READY_FOR_EVENTS = 'IC READY FOR EVENTS';
|
|
13
|
-
const INITIALIZING_STATUS = 'initializing';
|
|
14
|
-
const NONE_STATUS = '';
|
|
15
|
-
const RUNNING_STATUS = 'running';
|
|
16
|
-
const ENDED_STATUS = 'ended';
|
|
17
|
-
const ERROR = 'ERROR';
|
|
18
|
-
const OBEY_RECONNECT = 'obey-reconnect';
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* This defines and constructs a worker message.
|
|
22
|
-
* @param {String} type
|
|
23
|
-
* @param {Object} payload
|
|
24
|
-
*/
|
|
25
|
-
function WorkerMessage (type, payload) {
|
|
26
|
-
this.type = type;
|
|
27
|
-
this.payload = payload;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
WorkerMessage.prototype = {};
|
|
31
|
-
WorkerMessage.prototype.constructor = WorkerMessage;
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Returns the type of worker message
|
|
35
|
-
*/
|
|
36
|
-
WorkerMessage.prototype.getType = function getType () {
|
|
37
|
-
return this.type;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* returns the actual payload of message
|
|
42
|
-
*/
|
|
43
|
-
WorkerMessage.prototype.getPayload = function getPayload () {
|
|
44
|
-
return this.payload;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
WorkerMessage.TYPE = {
|
|
48
|
-
MESSAGE,
|
|
49
|
-
FLUSH,
|
|
50
|
-
BUSY,
|
|
51
|
-
INACTIVE,
|
|
52
|
-
RECONNECT,
|
|
53
|
-
UPDATE_APPLICATION_INFO,
|
|
54
|
-
IC_READY_FOR_EVENTS,
|
|
55
|
-
ERROR,
|
|
56
|
-
OBEY_RECONNECT
|
|
57
|
-
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* parses a Worker thread from simple object
|
|
62
|
-
* @param {Object} obj
|
|
63
|
-
*/
|
|
64
|
-
WorkerMessage.parseFromObject = function parseFromObject (obj) {
|
|
65
|
-
if (obj && obj.type && obj.payload) {
|
|
66
|
-
return new WorkerMessage(obj.type, obj.payload);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return false;
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
const WORKER_STATUS = {
|
|
73
|
-
NONE: NONE_STATUS,
|
|
74
|
-
INITIALIZING: INITIALIZING_STATUS,
|
|
75
|
-
RUNNING: RUNNING_STATUS,
|
|
76
|
-
ENDED: ENDED_STATUS
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
module.exports = {
|
|
80
|
-
WorkerMessage,
|
|
81
|
-
WORKER_STATUS
|
|
82
|
-
};
|