@newrelic/security-agent 2.1.1 → 2.3.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 +24 -0
- package/THIRD_PARTY_NOTICES.md +35 -4
- package/lib/instrumentation-security/core/event-constants.js +6 -3
- package/lib/instrumentation-security/hooks/crypto/nr-crypto.js +145 -0
- package/lib/instrumentation-security/hooks/express/nr-express.js +71 -3
- package/lib/instrumentation-security/hooks/fastify/nr-fastify.js +4 -7
- package/lib/instrumentation-security/hooks/graphql/nr-graphql.js +75 -0
- package/lib/instrumentation-security/hooks/http/nr-http.js +40 -5
- package/lib/instrumentation-security/hooks/native/nr-vm.js +46 -0
- package/lib/instrumentation-security/hooks/nextjs/nr-next.js +93 -0
- package/lib/instrumentation-security/index.js +43 -0
- package/lib/nr-security-agent/lib/core/Auth-headers.js +2 -1
- package/lib/nr-security-agent/lib/core/event.js +2 -1
- package/lib/nr-security-agent/lib/core/sec-util.js +5 -1
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
### v2.3.0 (2025-02-03)
|
|
2
|
+
#### Features
|
|
3
|
+
* Added Support for VM module
|
|
4
|
+
* IAST support for Next.js
|
|
5
|
+
* Support for Insecure settings i.e crypto, hash and random modules
|
|
6
|
+
|
|
7
|
+
#### Bug fixes
|
|
8
|
+
* Fix for special characters in ws header
|
|
9
|
+
* Fix for getting transaction in graphql instrumentation
|
|
10
|
+
* Fix for mongodb unit tests
|
|
11
|
+
|
|
12
|
+
#### Miscellaneous chores
|
|
13
|
+
* deps-dev: bump undici from v5.28.4 to v5.28.5
|
|
14
|
+
* Updated axios to v1.7.9
|
|
15
|
+
|
|
16
|
+
### v2.2.0 (2024-12-18)
|
|
17
|
+
#### Features
|
|
18
|
+
* Support for express 5.x
|
|
19
|
+
* IAST support for GraphQL
|
|
20
|
+
* Added support for trustboundary security events
|
|
21
|
+
|
|
22
|
+
#### Bug fixes
|
|
23
|
+
* Fix for empty route in fastify
|
|
24
|
+
|
|
1
25
|
### v2.1.1 (2024-11-07)
|
|
2
26
|
#### Bug fixes
|
|
3
27
|
* Fix for assignment to logger constant
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -18,6 +18,7 @@ code, the source code can be found at [https://github.com/newrelic/csec-node-age
|
|
|
18
18
|
* [check-disk-space](#check-disk-space)
|
|
19
19
|
* [content-type](#content-type)
|
|
20
20
|
* [cron](#cron)
|
|
21
|
+
* [docker-cli-js](#docker-cli-js)
|
|
21
22
|
* [fast-safe-stringify](#fast-safe-stringify)
|
|
22
23
|
* [find-package-json](#find-package-json)
|
|
23
24
|
* [hash.js](#hashjs)
|
|
@@ -79,7 +80,7 @@ code, the source code can be found at [https://github.com/newrelic/csec-node-age
|
|
|
79
80
|
|
|
80
81
|
### axios
|
|
81
82
|
|
|
82
|
-
This product includes source derived from [axios](https://github.com/axios/axios) ([v1.7.
|
|
83
|
+
This product includes source derived from [axios](https://github.com/axios/axios) ([v1.7.9](https://github.com/axios/axios/tree/v1.7.9)), distributed under the [MIT License](https://github.com/axios/axios/blob/v1.7.9/LICENSE):
|
|
83
84
|
|
|
84
85
|
```
|
|
85
86
|
# Copyright (c) 2014-present Matt Zabriskie & Collaborators
|
|
@@ -165,6 +166,36 @@ The above copyright notice and this permission notice shall be included in all c
|
|
|
165
166
|
|
|
166
167
|
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
167
168
|
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### docker-cli-js
|
|
172
|
+
|
|
173
|
+
This product includes source derived from [docker-cli-js](https://github.com/Quobject/docker-cli-js) ([v2.10.0](https://github.com/Quobject/docker-cli-js/tree/v2.10.0)), distributed under the [MIT License](https://github.com/Quobject/docker-cli-js/blob/v2.10.0/LICENSE):
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
The MIT License (MIT)
|
|
177
|
+
|
|
178
|
+
Copyright (c) 2016 Matthias Ludwig (mludwig@quobject.io)
|
|
179
|
+
|
|
180
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
181
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
182
|
+
in the Software without restriction, including without limitation the rights
|
|
183
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
184
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
185
|
+
furnished to do so, subject to the following conditions:
|
|
186
|
+
|
|
187
|
+
The above copyright notice and this permission notice shall be included in
|
|
188
|
+
all copies or substantial portions of the Software.
|
|
189
|
+
|
|
190
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
191
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
192
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
193
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
194
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
195
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
196
|
+
THE SOFTWARE.
|
|
197
|
+
|
|
198
|
+
|
|
168
199
|
```
|
|
169
200
|
|
|
170
201
|
### fast-safe-stringify
|
|
@@ -259,7 +290,7 @@ THE SOFTWARE.
|
|
|
259
290
|
|
|
260
291
|
### https-proxy-agent
|
|
261
292
|
|
|
262
|
-
This product includes source derived from [https-proxy-agent](https://github.com/TooTallNate/proxy-agents) ([v7.0.
|
|
293
|
+
This product includes source derived from [https-proxy-agent](https://github.com/TooTallNate/proxy-agents) ([v7.0.6](https://github.com/TooTallNate/proxy-agents/tree/v7.0.6)), distributed under the [MIT License](https://github.com/TooTallNate/proxy-agents/blob/v7.0.6/LICENSE):
|
|
263
294
|
|
|
264
295
|
```
|
|
265
296
|
(The MIT License)
|
|
@@ -512,7 +543,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|
|
512
543
|
|
|
513
544
|
### semver
|
|
514
545
|
|
|
515
|
-
This product includes source derived from [semver](https://github.com/npm/node-semver) ([v7.
|
|
546
|
+
This product includes source derived from [semver](https://github.com/npm/node-semver) ([v7.6.3](https://github.com/npm/node-semver/tree/v7.6.3)), distributed under the [ISC License](https://github.com/npm/node-semver/blob/v7.6.3/LICENSE):
|
|
516
547
|
|
|
517
548
|
```
|
|
518
549
|
The ISC License
|
|
@@ -1876,7 +1907,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
1876
1907
|
|
|
1877
1908
|
### mongodb-memory-server
|
|
1878
1909
|
|
|
1879
|
-
This product includes source derived from [mongodb-memory-server](https://github.com/nodkz/mongodb-memory-server) ([v8.
|
|
1910
|
+
This product includes source derived from [mongodb-memory-server](https://github.com/nodkz/mongodb-memory-server) ([v8.11.2](https://github.com/nodkz/mongodb-memory-server/tree/v8.11.2)), distributed under the [MIT License](https://github.com/nodkz/mongodb-memory-server/blob/v8.11.2/LICENSE.md):
|
|
1880
1911
|
|
|
1881
1912
|
```
|
|
1882
1913
|
The MIT License (MIT)
|
|
@@ -14,14 +14,15 @@ const EVENT_TYPE = {
|
|
|
14
14
|
HTTP_REQUEST: 'HTTP_REQUEST',
|
|
15
15
|
CODE_INJECTION: 'CODE_INJECTION',
|
|
16
16
|
XXE: 'XXE',
|
|
17
|
-
CIPHER: 'CIPHER',
|
|
18
17
|
HASH: 'HASH',
|
|
19
18
|
RANDOM: 'RANDOM',
|
|
20
19
|
UNVALIDATED_REDIRECT: 'UNVALIDATED_REDIRECT',
|
|
21
20
|
REFLECTED_XSS: 'REFLECTED_XSS',
|
|
22
21
|
XPATH: 'XPATH',
|
|
23
22
|
LDAP: 'LDAP',
|
|
24
|
-
SECURE_COOKIE: 'SECURE_COOKIE'
|
|
23
|
+
SECURE_COOKIE: 'SECURE_COOKIE',
|
|
24
|
+
TRUSTBOUNDARY: 'TRUSTBOUNDARY',
|
|
25
|
+
CRYPTO: 'CRYPTO',
|
|
25
26
|
}
|
|
26
27
|
const EVENT_CATEGORY = {
|
|
27
28
|
MYSQL: 'MYSQL',
|
|
@@ -42,7 +43,9 @@ const EVENT_CATEGORY = {
|
|
|
42
43
|
REFLECTED_XSS: 'REFLECTED_XSS',
|
|
43
44
|
XPATH: 'XPATH',
|
|
44
45
|
LDAP: 'LDAP',
|
|
45
|
-
SECURE_COOKIE: 'SECURE_COOKIE'
|
|
46
|
+
SECURE_COOKIE: 'SECURE_COOKIE',
|
|
47
|
+
TRUSTBOUNDARY: 'TRUSTBOUNDARY',
|
|
48
|
+
CIPHER: 'CIPHER',
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
module.exports = {
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: New Relic Software License v1.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
module.exports = initialize
|
|
7
|
+
const requestManager = require('../../core/request-manager');
|
|
8
|
+
const secUtils = require("../../core/sec-utils");
|
|
9
|
+
const API = require("../../../nr-security-api");
|
|
10
|
+
const securityMetaData = require('../../core/security-metadata');
|
|
11
|
+
const { EVENT_TYPE, EVENT_CATEGORY } = require('../../core/event-constants');
|
|
12
|
+
const { NR_CSEC_FUZZ_REQUEST_ID } = require('../../core/constants');
|
|
13
|
+
const logger = API.getLogger();
|
|
14
|
+
const NRLIB = 'newrelic/lib';
|
|
15
|
+
const SALIB = 'security-agent/lib'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Entry point of crypto module hook
|
|
19
|
+
* @param {*} shim
|
|
20
|
+
* @param {*} mod
|
|
21
|
+
* @param {*} moduleName
|
|
22
|
+
*/
|
|
23
|
+
function initialize(shim, mod, moduleName) {
|
|
24
|
+
if (API && API.getNRAgent() && API.getNRAgent().config.security.exclude_from_iast_scan.iast_detection_category.insecure_settings) {
|
|
25
|
+
logger.warn('insecure_settings detection is disabled');
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
logger.info('Instrumenting ' + moduleName)
|
|
29
|
+
cryptoCipherHooks(shim, mod, 'createCipheriv', moduleName);
|
|
30
|
+
cryptoHashHmacHooks(shim, mod, 'createHash', moduleName);
|
|
31
|
+
cryptoHashHmacHooks(shim, mod, 'createHmac', moduleName);
|
|
32
|
+
cryptoRandomHooks(shim, Math, 'random', "Math");
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* wrapper to hook crypto cipher methods
|
|
36
|
+
* @param {*} shim
|
|
37
|
+
* @param {*} mod
|
|
38
|
+
* @param {*} methodName
|
|
39
|
+
* @param {*} moduleName
|
|
40
|
+
*/
|
|
41
|
+
function cryptoCipherHooks(shim, mod, methodName, moduleName) {
|
|
42
|
+
shim.wrap(mod, methodName, function makeWrapper(shim, fn) {
|
|
43
|
+
logger.debug(`Instrumenting ${moduleName}.${methodName}`);
|
|
44
|
+
return function wrapper() {
|
|
45
|
+
const interceptedArgs = [arguments[0]];
|
|
46
|
+
shim.interceptedArgs = interceptedArgs;
|
|
47
|
+
const request = requestManager.getRequest(shim);
|
|
48
|
+
if (request && API.getSecAgent() && API.getSecAgent().status && API.getSecAgent().status.getStatus() === 'active') {
|
|
49
|
+
const traceObject = secUtils.getTraceObject(shim);
|
|
50
|
+
const secMetadata = securityMetaData.getSecurityMetaData(request, interceptedArgs, traceObject, secUtils.getExecutionId(), EVENT_TYPE.CRYPTO, EVENT_CATEGORY.CIPHER)
|
|
51
|
+
if (secMetadata.traceObject && secMetadata.traceObject.stacktrace && (secMetadata.traceObject.stacktrace[0].includes(NRLIB) || secMetadata.traceObject.stacktrace[0].includes(SALIB))) {
|
|
52
|
+
//do nothing
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
const secEvent = API.generateSecEvent(secMetadata);
|
|
56
|
+
this.secEvent = secEvent;
|
|
57
|
+
API.sendEvent(secEvent);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const result = fn.apply(this, arguments);
|
|
61
|
+
|
|
62
|
+
if (result && request && request.headers[NR_CSEC_FUZZ_REQUEST_ID]) {
|
|
63
|
+
API.generateExitEvent(this.secEvent);
|
|
64
|
+
delete this.secEvent
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* wrapper to hook crypto hash and mac methods
|
|
74
|
+
* @param {*} shim
|
|
75
|
+
* @param {*} mod
|
|
76
|
+
* @param {*} methodName
|
|
77
|
+
* @param {*} moduleName
|
|
78
|
+
*/
|
|
79
|
+
function cryptoHashHmacHooks(shim, mod, methodName, moduleName) {
|
|
80
|
+
shim.wrap(mod, methodName, function makeWrapper(shim, fn) {
|
|
81
|
+
logger.debug(`Instrumenting ${moduleName}.${methodName}`);
|
|
82
|
+
return function wrapper() {
|
|
83
|
+
const interceptedArgs = [arguments[0]];
|
|
84
|
+
shim.interceptedArgs = interceptedArgs;
|
|
85
|
+
const request = requestManager.getRequest(shim);
|
|
86
|
+
|
|
87
|
+
if (request && arguments[0] !== 'sha256' && API.getSecAgent() && API.getSecAgent().status && API.getSecAgent().status.getStatus() === 'active') {
|
|
88
|
+
const traceObject = secUtils.getTraceObject(shim);
|
|
89
|
+
const secMetadata = securityMetaData.getSecurityMetaData(request, interceptedArgs, traceObject, secUtils.getExecutionId(), EVENT_TYPE.HASH, EVENT_CATEGORY.HASH)
|
|
90
|
+
if (secMetadata.traceObject && secMetadata.traceObject.stacktrace && (secMetadata.traceObject.stacktrace[0].includes(NRLIB) || secMetadata.traceObject.stacktrace[0].includes(SALIB))) {
|
|
91
|
+
//do nothing
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
const secEvent = API.generateSecEvent(secMetadata);
|
|
95
|
+
this.secEvent = secEvent;
|
|
96
|
+
API.sendEvent(secEvent);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const result = fn.apply(this, arguments);
|
|
100
|
+
if (result && request && request.headers[NR_CSEC_FUZZ_REQUEST_ID] && arguments[0] !== 'sha256') {
|
|
101
|
+
API.generateExitEvent(this.secEvent);
|
|
102
|
+
delete this.secEvent
|
|
103
|
+
}
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Wrapper for random hooks
|
|
110
|
+
* @param {*} shim
|
|
111
|
+
* @param {*} mod
|
|
112
|
+
* @param {*} methodName
|
|
113
|
+
* @param {*} moduleName
|
|
114
|
+
*/
|
|
115
|
+
function cryptoRandomHooks(shim, mod, methodName, moduleName) {
|
|
116
|
+
shim.wrap(mod, methodName, function makeWrapper(shim, fn) {
|
|
117
|
+
logger.debug(`Instrumenting ${moduleName}.${methodName}`);
|
|
118
|
+
return function wrapper() {
|
|
119
|
+
const interceptedArgs = ["Math.random"];
|
|
120
|
+
shim.interceptedArgs = interceptedArgs;
|
|
121
|
+
const request = requestManager.getRequest(shim);
|
|
122
|
+
if (request && API.getSecAgent() && API.getSecAgent().status && API.getSecAgent().status.getStatus() === 'active') {
|
|
123
|
+
const traceObject = secUtils.getTraceObject(shim);
|
|
124
|
+
const secMetadata = securityMetaData.getSecurityMetaData(request, interceptedArgs, traceObject, secUtils.getExecutionId(), EVENT_TYPE.RANDOM, EVENT_CATEGORY.WEAKRANDOM)
|
|
125
|
+
if (secMetadata.traceObject && secMetadata.traceObject.stacktrace && secMetadata.traceObject.stacktrace[0] && (secMetadata.traceObject.stacktrace[0].includes(NRLIB) || secMetadata.traceObject.stacktrace[0].includes(SALIB))) {
|
|
126
|
+
//do nothing
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
const secEvent = API.generateSecEvent(secMetadata);
|
|
130
|
+
this.secEvent = secEvent;
|
|
131
|
+
API.sendEvent(secEvent);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
}
|
|
135
|
+
const result = fn.apply(this, arguments);
|
|
136
|
+
if (result && request && request.headers[NR_CSEC_FUZZ_REQUEST_ID]) {
|
|
137
|
+
API.generateExitEvent(this.secEvent);
|
|
138
|
+
delete this.secEvent
|
|
139
|
+
}
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
|
|
@@ -30,12 +30,14 @@ module.exports = function initialize(shim, express) {
|
|
|
30
30
|
|
|
31
31
|
if (express.Router.use) {
|
|
32
32
|
wrapExpress4(shim, express)
|
|
33
|
-
}
|
|
33
|
+
}
|
|
34
|
+
else if (express.Router.prototype) {
|
|
35
|
+
wrapExpress5(shim, express)
|
|
36
|
+
}
|
|
34
37
|
if(API && API.getNRAgent() && !API.getNRAgent().config.security.exclude_from_iast_scan.iast_detection_category.invalid_file_access){
|
|
35
38
|
expressFileHook(shim, express && express.response, 'download')
|
|
36
39
|
expressFileHook(shim, express && express.response, 'sendFile')
|
|
37
40
|
}
|
|
38
|
-
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
/**
|
|
@@ -121,7 +123,7 @@ function extractParams(shim, req) {
|
|
|
121
123
|
* @param {*} mod
|
|
122
124
|
* @param {*} fun
|
|
123
125
|
*/
|
|
124
|
-
function expressFileHook(shim, mod, fun){
|
|
126
|
+
function expressFileHook(shim, mod, fun) {
|
|
125
127
|
shim.wrap(mod, fun, function makeFAWrapper(shim, fn) {
|
|
126
128
|
if (!shim.isFunction(fn)) {
|
|
127
129
|
return fn
|
|
@@ -149,4 +151,70 @@ function expressFileHook(shim, mod, fun){
|
|
|
149
151
|
});
|
|
150
152
|
}
|
|
151
153
|
|
|
154
|
+
/**
|
|
155
|
+
* Wrapper to hook express version 5.x route method
|
|
156
|
+
* @param {*} shim
|
|
157
|
+
* @param {*} express
|
|
158
|
+
*/
|
|
159
|
+
function wrapExpress5(shim, express) {
|
|
160
|
+
shim.wrap(express.Router.prototype, 'route', function wrapRoute(shim, fn) {
|
|
161
|
+
if (!shim.isFunction(fn)) {
|
|
162
|
+
return fn
|
|
163
|
+
}
|
|
164
|
+
logger.debug('Instrumenting express.Router.prototype.route');
|
|
165
|
+
return function wrappedRoute() {
|
|
166
|
+
try {
|
|
167
|
+
const stakTrace = secUtils.traceElementForRoute();
|
|
168
|
+
const splittedStack = stakTrace[0].split(DOUBLE_DOLLAR);
|
|
169
|
+
const key = lodash.upperCase(splittedStack[1]) + ATTHERATE + arguments[0];
|
|
170
|
+
routeManager.setRoute(key, splittedStack[0]);
|
|
171
|
+
} catch (error) {
|
|
172
|
+
|
|
173
|
+
}
|
|
174
|
+
const route = fn.apply(this, arguments)
|
|
175
|
+
return route;
|
|
176
|
+
}
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
module.exports.wrapRouter = function wrapExpress5Router(shim, mod) {
|
|
182
|
+
let layer = shim.require('./lib/layer');
|
|
183
|
+
shim.wrap(layer.prototype, 'match', function wrapParam(shim, fn) {
|
|
184
|
+
if (!shim.isFunction(fn)) {
|
|
185
|
+
return fn
|
|
186
|
+
}
|
|
187
|
+
logger.debug('Instrumenting router.layer.match');
|
|
188
|
+
return function wrappedParam() {
|
|
189
|
+
const route = fn.apply(this, arguments);
|
|
190
|
+
|
|
191
|
+
try {
|
|
192
|
+
const uri = this.route.path;
|
|
193
|
+
const params = this.params;
|
|
194
|
+
const transaction = shim.tracer.getTransaction();
|
|
195
|
+
if (transaction) {
|
|
196
|
+
let request = requestManager.getRequestFromId(transaction.id);
|
|
197
|
+
if (params && request) {
|
|
198
|
+
Object.keys(params).forEach(function (key) {
|
|
199
|
+
if (params[key]) {
|
|
200
|
+
if (!request.parameterMap[key]) {
|
|
201
|
+
request.parameterMap[key] = new Array(params[key].toString());
|
|
202
|
+
requestManager.setRequest(transaction.id, request);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
if (uri && request) {
|
|
208
|
+
request.uri = uri;
|
|
209
|
+
requestManager.setRequest(transaction.id, request);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
} catch (error) {
|
|
213
|
+
logger.debug("Error while getting path params via router module", error);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return route
|
|
217
|
+
}
|
|
218
|
+
})
|
|
219
|
+
}
|
|
152
220
|
|
|
@@ -10,7 +10,6 @@ const { ATTHERATE, DOUBLE_DOLLAR } = require('../../core/constants');
|
|
|
10
10
|
const lodash = require('lodash');
|
|
11
11
|
const routeManager = require('../../core/route-manager');
|
|
12
12
|
const semver = require('semver')
|
|
13
|
-
const url = require('url');
|
|
14
13
|
const API = require("../../../nr-security-api");
|
|
15
14
|
const logger = API.getLogger();
|
|
16
15
|
|
|
@@ -119,12 +118,10 @@ function setupExports(original, wrappedExport) {
|
|
|
119
118
|
*/
|
|
120
119
|
function extractParams(shim, req) {
|
|
121
120
|
try {
|
|
122
|
-
const reqURL = req.url || req.raw.url;
|
|
123
|
-
const parsedURI = url.parse(reqURL).pathname;
|
|
124
121
|
const transaction = shim.tracer.getTransaction();
|
|
125
122
|
if (transaction) {
|
|
126
123
|
let request = requestManager.getRequestFromId(transaction.id);
|
|
127
|
-
if (req.params &&
|
|
124
|
+
if (req.params && request) {
|
|
128
125
|
Object.keys(req.params).forEach(function (key) {
|
|
129
126
|
if (req.params[key]) {
|
|
130
127
|
if (!request.parameterMap[key]) {
|
|
@@ -144,9 +141,9 @@ function extractParams(shim, req) {
|
|
|
144
141
|
}
|
|
145
142
|
});
|
|
146
143
|
}
|
|
147
|
-
|
|
148
|
-
if (
|
|
149
|
-
request.uri =
|
|
144
|
+
const txInfo = lodash.get(req, Object.getOwnPropertySymbols(req).find(symbol => symbol.toString() === 'Symbol(fastify.context)'));
|
|
145
|
+
if (request && txInfo && txInfo.config && txInfo.config.url) {
|
|
146
|
+
request.uri = txInfo.config.url;
|
|
150
147
|
requestManager.setRequest(transaction.id, request);
|
|
151
148
|
}
|
|
152
149
|
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: New Relic Software License v1.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Express middleware generates traces where middleware are considered siblings
|
|
10
|
+
* (ended on 'next' invocation) and not nested. Middlware are nested below the
|
|
11
|
+
* routers they are mounted to.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const requestManager = require("../../core/request-manager");
|
|
15
|
+
const { QUESTIONMARK } = require('../../core/constants');
|
|
16
|
+
const API = require("../../../nr-security-api");
|
|
17
|
+
const logger = API.getLogger();
|
|
18
|
+
const { APPLICATION_JSON } = require('../../core/constants');
|
|
19
|
+
let querystring = require('querystring');
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
module.exports = function initialize(shim, mod) {
|
|
23
|
+
logger.info("Instrumenting graphql");
|
|
24
|
+
|
|
25
|
+
shim.wrap(mod, 'execute', function wrapExecute(shim, fn) {
|
|
26
|
+
if (!shim.isFunction(fn)) {
|
|
27
|
+
return fn;
|
|
28
|
+
}
|
|
29
|
+
return function wrappedExecute() {
|
|
30
|
+
const transaction = shim.tracer.getTransaction();
|
|
31
|
+
try {
|
|
32
|
+
if (transaction) {
|
|
33
|
+
let request = requestManager.getRequestFromId(transaction.id);
|
|
34
|
+
let customDataType = {};
|
|
35
|
+
//check for query parms
|
|
36
|
+
if (request.headers['x-apollo-operation-name']) {
|
|
37
|
+
const queryString = request.url.split(QUESTIONMARK)[1];
|
|
38
|
+
const parsedQueryString = querystring.parse(queryString);
|
|
39
|
+
let allValues = Object.values(parsedQueryString);
|
|
40
|
+
for (let index = 0; index < allValues.length; index++) {
|
|
41
|
+
const element = allValues[index];
|
|
42
|
+
if (element.startsWith('query')) {
|
|
43
|
+
customDataType['*.query'] = 'GRAPHQL_QUERY';
|
|
44
|
+
}
|
|
45
|
+
if (element.startsWith('variables')) {
|
|
46
|
+
customDataType['*.variables'] = 'GRAPHQL_VARIABLE';
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
request.customDataType = customDataType;
|
|
50
|
+
requestManager.setRequest(transaction.id, request);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
//check for body
|
|
54
|
+
if (request.headers['content-type'] === APPLICATION_JSON) {
|
|
55
|
+
const requestBody = JSON.parse(request.body);
|
|
56
|
+
if (requestBody.query) {
|
|
57
|
+
customDataType['*.query'] = 'GRAPHQL_QUERY';
|
|
58
|
+
}
|
|
59
|
+
if (requestBody.variables) {
|
|
60
|
+
customDataType['*.variables'] = 'GRAPHQL_VARIABLE';
|
|
61
|
+
}
|
|
62
|
+
request.customDataType = customDataType;
|
|
63
|
+
requestManager.setRequest(transaction.id, request);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
} catch (error) {
|
|
68
|
+
logger.debug("Error while processing graphql http request", error);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return fn.apply(this, arguments);
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
module.exports = initialize
|
|
7
7
|
const requestManager = require('../../core/request-manager');
|
|
8
|
-
const { NR_CSEC_FUZZ_REQUEST_ID, QUESTION_MARK, EMPTY_STRING, UTF8, CONTENT_TYPE, TEXT_HTML, APPLICATION_JSON, APPLICATION_XML, APPLICATION_XHTML, TEXT_PLAIN, APPLICATION_X_FORM_URLENCODED, MULTIPART_FORM_DATA, COMMA, SEMI_COLON, EQUAL, SECURE, HTTPONLY, SAMESITE, STRICT } = require('../../core/constants');
|
|
8
|
+
const { NR_CSEC_FUZZ_REQUEST_ID, QUESTION_MARK, EMPTY_STRING, UTF8, CONTENT_TYPE, TEXT_HTML, APPLICATION_JSON, APPLICATION_XML, APPLICATION_XHTML, TEXT_PLAIN, APPLICATION_X_FORM_URLENCODED, MULTIPART_FORM_DATA, COMMA, SEMI_COLON, EQUAL, SECURE, HTTPONLY, SAMESITE, STRICT, OBJECT } = require('../../core/constants');
|
|
9
9
|
const ARRAY_TYPE = 'Array';
|
|
10
10
|
const STRING_TYPE = 'string';
|
|
11
11
|
const BUFFER_TYPE = 'Buffer';
|
|
@@ -446,6 +446,9 @@ function responseHook(resp, req, shim) {
|
|
|
446
446
|
}
|
|
447
447
|
try {
|
|
448
448
|
secureCookieCheck(response, shim);
|
|
449
|
+
if (response && response.req && response.req.session) {
|
|
450
|
+
trustBoundaryCheck(response.req.session, shim)
|
|
451
|
+
}
|
|
449
452
|
} catch (error) {
|
|
450
453
|
logger.debug("Error while generating secure cookie event");
|
|
451
454
|
}
|
|
@@ -456,8 +459,8 @@ function responseHook(resp, req, shim) {
|
|
|
456
459
|
const policy = API.getPolicy();
|
|
457
460
|
const dynamicScanningFlag = policy.data ? (policy.data.vulnerabilityScan?.enabled && policy.data.vulnerabilityScan.iastScan.enabled) : false;
|
|
458
461
|
const type = response.getHeader(CONTENT_TYPE);
|
|
459
|
-
let isUnsupportedType = isUnsupportedContentType(type);
|
|
460
|
-
|
|
462
|
+
let isUnsupportedType = isUnsupportedContentType(type, response);
|
|
463
|
+
|
|
461
464
|
if (request && (construct || dynamicScanningFlag) && !isUnsupportedType) {
|
|
462
465
|
const args = [];
|
|
463
466
|
args.push(construct);
|
|
@@ -478,8 +481,11 @@ function responseHook(resp, req, shim) {
|
|
|
478
481
|
* @param {*} conType
|
|
479
482
|
* @returns
|
|
480
483
|
*/
|
|
481
|
-
function isUnsupportedContentType(conType) {
|
|
484
|
+
function isUnsupportedContentType(conType, response) {
|
|
482
485
|
try {
|
|
486
|
+
if(response.getHeaders()['etag']){
|
|
487
|
+
return false;
|
|
488
|
+
}
|
|
483
489
|
if (!conType) {
|
|
484
490
|
return true;
|
|
485
491
|
}
|
|
@@ -531,7 +537,7 @@ function isUnsupportedContentType(conType) {
|
|
|
531
537
|
function responseBodyCompute(response, args) {
|
|
532
538
|
let encoding = UTF8;
|
|
533
539
|
const type = response.getHeader(CONTENT_TYPE);
|
|
534
|
-
let isUnsupportedType = isUnsupportedContentType(type);
|
|
540
|
+
let isUnsupportedType = isUnsupportedContentType(type, response);
|
|
535
541
|
if (isUnsupportedType) {
|
|
536
542
|
return;
|
|
537
543
|
}
|
|
@@ -730,3 +736,32 @@ function truncateStringToBytes(inputString, maxBytes) {
|
|
|
730
736
|
return truncatedString;
|
|
731
737
|
}
|
|
732
738
|
|
|
739
|
+
/**
|
|
740
|
+
* Utility to generate trustboundary events.
|
|
741
|
+
* @param {*} sessionObject
|
|
742
|
+
* @param {*} shim
|
|
743
|
+
*/
|
|
744
|
+
function trustBoundaryCheck(sessionObject, shim) {
|
|
745
|
+
try {
|
|
746
|
+
const request = requestManager.getRequest(shim);
|
|
747
|
+
let params = [];
|
|
748
|
+
Object.keys(sessionObject).forEach(key => {
|
|
749
|
+
if (sessionObject[key] && typeof sessionObject[key] != OBJECT) {
|
|
750
|
+
params.push(String(key));
|
|
751
|
+
params.push(String(sessionObject[key]));
|
|
752
|
+
}
|
|
753
|
+
});
|
|
754
|
+
if (!lodash.isEmpty(params)) {
|
|
755
|
+
const traceObject = secUtils.getTraceObject(shim);
|
|
756
|
+
const secMetadata = securityMetaData.getSecurityMetaData(request, params, traceObject, secUtils.getExecutionId(), EVENT_TYPE.TRUSTBOUNDARY, EVENT_CATEGORY.TRUSTBOUNDARY)
|
|
757
|
+
const secEvent = API.generateSecEvent(secMetadata);
|
|
758
|
+
API.sendEvent(secEvent);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
} catch (error) {
|
|
762
|
+
logger.debug("Error while processing trustboundary", error);
|
|
763
|
+
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
}
|
|
767
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module.exports = initialize;
|
|
2
|
+
const requestManager = require("../../core/request-manager");
|
|
3
|
+
const secUtils = require("../../core/sec-utils");
|
|
4
|
+
const API = require("../../../nr-security-api");
|
|
5
|
+
const securityMetaData = require('../../core/security-metadata');
|
|
6
|
+
const { NR_CSEC_FUZZ_REQUEST_ID } = require('../../core/constants');
|
|
7
|
+
const logger = API.getLogger();
|
|
8
|
+
|
|
9
|
+
function initialize(shim, vm, moduleName) {
|
|
10
|
+
logger.info('Instrumenting', moduleName);
|
|
11
|
+
vmHooks(shim, vm, 'runInNewContext', moduleName);
|
|
12
|
+
vmHooks(shim, vm, 'runInThisContext', moduleName);
|
|
13
|
+
vmHooks(shim, vm, 'runInContext', moduleName);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Wrapper to hook vm methods
|
|
18
|
+
* @param {*} shim
|
|
19
|
+
* @param {*} vm
|
|
20
|
+
* @param {*} method
|
|
21
|
+
* @param {*} moduleName
|
|
22
|
+
*/
|
|
23
|
+
function vmHooks(shim, vm, method, moduleName) {
|
|
24
|
+
shim.wrap(vm, method, function makeWrapper(shim, fn) {
|
|
25
|
+
logger.debug(`Instrumenting ${moduleName}.${method}`);
|
|
26
|
+
return function wrapper() {
|
|
27
|
+
const interceptedArgs = [arguments[0]];
|
|
28
|
+
shim.interceptedArgs = interceptedArgs;
|
|
29
|
+
const request = requestManager.getRequest(shim);
|
|
30
|
+
if (request) {
|
|
31
|
+
const traceObject = secUtils.getTraceObject(shim);
|
|
32
|
+
const secMetadata = securityMetaData.getSecurityMetaData(request, interceptedArgs, traceObject, secUtils.getExecutionId(), "JAVASCRIPT_INJECTION", "JAVASCRIPT_INJECTION")
|
|
33
|
+
const secEvent = API.generateSecEvent(secMetadata);
|
|
34
|
+
this.secEvent = secEvent;
|
|
35
|
+
API.sendEvent(secEvent);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const result = fn.apply(this, arguments);
|
|
39
|
+
if (result && request && request.headers[NR_CSEC_FUZZ_REQUEST_ID]) {
|
|
40
|
+
API.generateExitEvent(this.secEvent);
|
|
41
|
+
delete this.secEvent
|
|
42
|
+
}
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: New Relic Pre-Release
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
const requestManager = require("../../core/request-manager");
|
|
8
|
+
const API = require("../../../nr-security-api");
|
|
9
|
+
const logger = API.getLogger();
|
|
10
|
+
|
|
11
|
+
const semver = require('semver')
|
|
12
|
+
|
|
13
|
+
module.exports = function initialize(shim, nextjs) {
|
|
14
|
+
const nextVersion = shim.require('./package.json').version
|
|
15
|
+
logger.info("Instrumenting nextjs", nextVersion);
|
|
16
|
+
|
|
17
|
+
const nextServer = nextjs.default;
|
|
18
|
+
hookRunAPI(shim, nextServer.prototype, nextVersion);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Wrapper for Server.prototype.runApi
|
|
23
|
+
* @param {*} shim
|
|
24
|
+
* @param {*} mod
|
|
25
|
+
* @param {*} nextVersion
|
|
26
|
+
*/
|
|
27
|
+
function hookRunAPI(shim, mod, nextVersion) {
|
|
28
|
+
shim.wrap(mod, 'runApi', function wrapRunApi(shim, originalFn) {
|
|
29
|
+
if (!shim.isFunction(originalFn)) {
|
|
30
|
+
return originalFn
|
|
31
|
+
}
|
|
32
|
+
logger.debug("Instrumenting Server.prototype.runApi");
|
|
33
|
+
return function wrappedRunApi() {
|
|
34
|
+
try {
|
|
35
|
+
const { page, params } = extractAttrs(arguments, nextVersion)
|
|
36
|
+
extractParams(shim, page, params);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
logger.debug("Error while processing path paramters");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return originalFn.apply(this, arguments)
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Extracts the page and params from an API request
|
|
48
|
+
*
|
|
49
|
+
* @param {object} args arguments to runApi
|
|
50
|
+
* @param {string} version next.js version
|
|
51
|
+
* @returns {object} { page, params }
|
|
52
|
+
*/
|
|
53
|
+
function extractAttrs(args, version) {
|
|
54
|
+
let params
|
|
55
|
+
let page
|
|
56
|
+
if (semver.gte(version, '13.4.13')) {
|
|
57
|
+
const [, , , match] = args
|
|
58
|
+
page = match?.definition?.pathname
|
|
59
|
+
params = { ...match?.params }
|
|
60
|
+
} else {
|
|
61
|
+
;[, , , params, page] = args
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return { params, page }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Utility to extract path params
|
|
69
|
+
* @param {*} page
|
|
70
|
+
* @param {*} params
|
|
71
|
+
*/
|
|
72
|
+
function extractParams(shim, page, params) {
|
|
73
|
+
try {
|
|
74
|
+
const transaction = shim.tracer.getTransaction();
|
|
75
|
+
if (transaction) {
|
|
76
|
+
let request = requestManager.getRequestFromId(transaction.id);
|
|
77
|
+
Object.keys(params).forEach(function (key) {
|
|
78
|
+
if (params[key]) {
|
|
79
|
+
if (!request.parameterMap[key]) {
|
|
80
|
+
request.parameterMap[key] = new Array(params[key].toString());
|
|
81
|
+
requestManager.setRequest(transaction.id, request);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
if (request && page) {
|
|
86
|
+
request.uri = page;
|
|
87
|
+
requestManager.setRequest(transaction.id, request);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
} catch (error) {
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
@@ -235,3 +235,46 @@ newrelic.instrument({
|
|
|
235
235
|
}
|
|
236
236
|
})
|
|
237
237
|
|
|
238
|
+
newrelic.instrument({
|
|
239
|
+
moduleName: 'graphql/execution/execute',
|
|
240
|
+
isEsm: true,
|
|
241
|
+
onRequire: require('./hooks/graphql/nr-graphql'),
|
|
242
|
+
onError: function intrumentErrorHandler(err) {
|
|
243
|
+
logger.error(err.message, err.stack)
|
|
244
|
+
}
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
newrelic.instrument({
|
|
248
|
+
moduleName: 'router',
|
|
249
|
+
isEsm: true,
|
|
250
|
+
onRequire: require('./hooks/express/nr-express').wrapRouter,
|
|
251
|
+
onError: function intrumentErrorHandler(err) {
|
|
252
|
+
logger.error(err.message, err.stack)
|
|
253
|
+
}
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
newrelic.instrument({
|
|
257
|
+
moduleName: 'crypto',
|
|
258
|
+
onRequire: require('./hooks/crypto/nr-crypto'),
|
|
259
|
+
onError: function intrumentErrorHandler(err) {
|
|
260
|
+
logger.error(err.message, err.stack)
|
|
261
|
+
}
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
newrelic.instrumentWebframework({
|
|
265
|
+
moduleName: 'next/dist/server/next-server',
|
|
266
|
+
isEsm: true,
|
|
267
|
+
onRequire: require('./hooks/nextjs/nr-next'),
|
|
268
|
+
onError: function intrumentErrorHandler(err) {
|
|
269
|
+
logger.error(err.message, err.stack)
|
|
270
|
+
}
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
newrelic.instrument({
|
|
274
|
+
moduleName: 'vm',
|
|
275
|
+
isEsm: true,
|
|
276
|
+
onRequire: require('./hooks/native/nr-vm'),
|
|
277
|
+
onError: function intrumentErrorHandler(err) {
|
|
278
|
+
logger.error(err.message, err.stack)
|
|
279
|
+
}
|
|
280
|
+
})
|
|
@@ -36,7 +36,8 @@ function AuthHeaders() {
|
|
|
36
36
|
authHeaders['NR-ACCOUNT-ID'] = NRAgent.config.account_id;
|
|
37
37
|
authHeaders['NR-LICENSE-KEY'] = NRAgent ? NRAgent.config.license_key : '';
|
|
38
38
|
authHeaders["NR-CSEC-IAST-DATA-TRANSFER-MODE"] = "PULL";
|
|
39
|
-
|
|
39
|
+
const entityName = metadata['entity.name'] ? metadata['entity.name'] : '';
|
|
40
|
+
authHeaders['NR-CSEC-ENTITY-NAME'] = encodeURIComponent(entityName);
|
|
40
41
|
authHeaders['NR-CSEC-ENTITY-GUID'] = metadata['entity.guid'] ? metadata['entity.guid'] : '';
|
|
41
42
|
let instanceCount = parseInt(NRAgent.config.security.scan_controllers.scan_instance_count);
|
|
42
43
|
if (isNaN(instanceCount)) {
|
|
@@ -12,6 +12,7 @@ const API = require('../../../nr-security-api');
|
|
|
12
12
|
const NRAgent = API.getNRAgent();
|
|
13
13
|
const lodash = require('lodash');
|
|
14
14
|
const commonUtils = require('./commonUtils');
|
|
15
|
+
const crypto = require('crypto');
|
|
15
16
|
/**
|
|
16
17
|
* BasicInfo Structure, which is applicatble to each
|
|
17
18
|
* Event generated from agent.
|
|
@@ -99,7 +100,7 @@ function SecEvent(fileName, funcName, lineNumber, argument, eid, applicationInfo
|
|
|
99
100
|
const dynamicScanning = vulnerabilityScan.enabled && vulnerabilityScan.iastScan.enabled;
|
|
100
101
|
this.isIASTEnable = dynamicScanning;
|
|
101
102
|
if (this.isIASTEnable) {
|
|
102
|
-
this.id = eid + Math.floor(
|
|
103
|
+
this.id = eid + Math.floor(crypto.randomInt(100) * (100000 - 1) + 1);
|
|
103
104
|
} else {
|
|
104
105
|
this.id = eid;
|
|
105
106
|
}
|
|
@@ -29,6 +29,10 @@ const initLogger = logs.getInitLogger();
|
|
|
29
29
|
|
|
30
30
|
const NODE_SER = 'node-serialize/lib/serialize.js';
|
|
31
31
|
const SECURE_COOKIE = 'SECURE_COOKIE';
|
|
32
|
+
const TRUSTBOUNDARY = 'TRUSTBOUNDARY';
|
|
33
|
+
const HASH = "HASH";
|
|
34
|
+
const CRYPTO = "CRYPTO";
|
|
35
|
+
const RANDOM = "RANDOM";
|
|
32
36
|
|
|
33
37
|
const insecureSettingApiIdSet = new Set();
|
|
34
38
|
|
|
@@ -110,7 +114,7 @@ function generateSecEvent(securityMetadata) {
|
|
|
110
114
|
|
|
111
115
|
let apiId = shaUtil.getSHA256ForData(traceObject.stacktrace.join('|') + uri);
|
|
112
116
|
apiId = securityMetadata.eventType + HYPHEN + apiId;
|
|
113
|
-
if (securityMetadata.eventType == SECURE_COOKIE) {
|
|
117
|
+
if (securityMetadata.eventType == SECURE_COOKIE || securityMetadata.eventType == CRYPTO || securityMetadata.eventType == HASH || securityMetadata.eventType == RANDOM) {
|
|
114
118
|
if (insecureSettingApiIdSet.has(apiId)) {
|
|
115
119
|
return;
|
|
116
120
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@newrelic/security-agent",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "New Relic Security Agent for Node.js",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"jsonVersion": "1.2.9",
|
|
@@ -39,10 +39,11 @@
|
|
|
39
39
|
"url": "https://github.com/newrelic/csec-node-agent.git"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"axios": "^1.7.
|
|
42
|
+
"axios": "^1.7.9",
|
|
43
43
|
"check-disk-space": "^3.4.0",
|
|
44
44
|
"content-type": "^1.0.5",
|
|
45
45
|
"cron": "^3.1.7",
|
|
46
|
+
"docker-cli-js": "^2.10.0",
|
|
46
47
|
"fast-safe-stringify": "^2.1.1",
|
|
47
48
|
"find-package-json": "^1.2.0",
|
|
48
49
|
"hash.js": "^1.1.7",
|