@contrast/protect 1.42.0 → 1.44.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/lib/input-analysis/handlers.js +8 -5
- package/lib/input-analysis/install/body-parser1.js +2 -1
- package/lib/input-analysis/install/http.js +3 -3
- package/lib/input-analysis/install/http.test.js +7 -1
- package/lib/input-analysis/ip-analysis.js +1 -1
- package/lib/input-analysis/virtual-patches.js +3 -3
- package/lib/input-tracing/handlers/index.js +1 -1
- package/lib/make-response-blocker.js +1 -1
- package/lib/make-source-context.js +1 -1
- package/lib/policy.js +8 -5
- package/lib/semantic-analysis/handlers.js +7 -3
- package/lib/semantic-analysis/utils/xml-analysis.js +3 -3
- package/package.json +11 -11
|
@@ -24,9 +24,12 @@ const {
|
|
|
24
24
|
traverseKeysAndValues,
|
|
25
25
|
traverseValues,
|
|
26
26
|
InputType,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
primordials: {
|
|
28
|
+
ArrayPrototypeJoin,
|
|
29
|
+
ArrayPrototypeSlice,
|
|
30
|
+
StringPrototypeToLowerCase,
|
|
31
|
+
StringPrototypeSplit,
|
|
32
|
+
}
|
|
30
33
|
} = require('@contrast/common');
|
|
31
34
|
|
|
32
35
|
//
|
|
@@ -256,7 +259,7 @@ module.exports = function (core) {
|
|
|
256
259
|
resultsList.push({
|
|
257
260
|
ruleId: item.ruleId,
|
|
258
261
|
inputType: 'UrlParameter',
|
|
259
|
-
path:
|
|
262
|
+
path: ArrayPrototypeSlice.call(path),
|
|
260
263
|
key: path.pop(), // there should always be at least the param name
|
|
261
264
|
value,
|
|
262
265
|
score: item.score,
|
|
@@ -692,7 +695,7 @@ module.exports = function (core) {
|
|
|
692
695
|
const result = {
|
|
693
696
|
ruleId: item.ruleId,
|
|
694
697
|
inputType: `${inputTypeStr}${type}`,
|
|
695
|
-
path: mongoPath ||
|
|
698
|
+
path: mongoPath || ArrayPrototypeSlice.call(path),
|
|
696
699
|
key: type === 'Key' ? value : path[path.length - 1],
|
|
697
700
|
value,
|
|
698
701
|
score: item.score,
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
|
+
const { primordials: { JSONParse } } = require('@contrast/common');
|
|
18
19
|
const { isSecurityException } = require('../../security-exception');
|
|
19
20
|
|
|
20
21
|
module.exports = (core) => {
|
|
@@ -35,7 +36,7 @@ module.exports = (core) => {
|
|
|
35
36
|
|
|
36
37
|
if (fnName === 'bodyParser.text' && typeof req.body === 'string') {
|
|
37
38
|
try {
|
|
38
|
-
sourceContext.parsedBody =
|
|
39
|
+
sourceContext.parsedBody = JSONParse(req.body);
|
|
39
40
|
} catch (err) {
|
|
40
41
|
logger.error({ err }, 'Error parsing with bodyParser.text()');
|
|
41
42
|
origNext();
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
|
-
const { Event, StringPrototypeToLowerCase } = require('@contrast/common');
|
|
18
|
+
const { Event, primordials: { StringPrototypeToLowerCase, ArrayPrototypeSlice } } = require('@contrast/common');
|
|
19
19
|
const { patchType } = require('../constants');
|
|
20
20
|
|
|
21
21
|
module.exports = function (core) {
|
|
@@ -38,7 +38,7 @@ module.exports = function (core) {
|
|
|
38
38
|
function removeCookies(headers) {
|
|
39
39
|
for (let i = 0; i < headers.length; i += 2) {
|
|
40
40
|
if (headers[i] === 'cookies') {
|
|
41
|
-
headers =
|
|
41
|
+
headers = ArrayPrototypeSlice.call(headers);
|
|
42
42
|
headers.splice(i, 2);
|
|
43
43
|
}
|
|
44
44
|
}
|
|
@@ -94,7 +94,7 @@ module.exports = function (core) {
|
|
|
94
94
|
const connectInputs = {
|
|
95
95
|
headers: removeCookies(headers),
|
|
96
96
|
uriPath,
|
|
97
|
-
method:StringPrototypeToLowerCase.call(method),
|
|
97
|
+
method: StringPrototypeToLowerCase.call(method),
|
|
98
98
|
};
|
|
99
99
|
|
|
100
100
|
if (inputAnalysis.virtualPatchesEvaluators?.length) {
|
|
@@ -10,6 +10,10 @@ describe('protect input-analysis http', function () {
|
|
|
10
10
|
|
|
11
11
|
describe('initialization', function () {
|
|
12
12
|
let core, httpInstr, mockServer;
|
|
13
|
+
// this captures the sinon stub before it is wrapped by Perf so we can
|
|
14
|
+
// determine if it was called/not called as expected. if we don't do this
|
|
15
|
+
// the core.depHooks.install() will be replaced by the Perf wrapper and
|
|
16
|
+
// sinon will complain that it's not a spy/call-to-spy.
|
|
13
17
|
|
|
14
18
|
beforeEach(function () {
|
|
15
19
|
({ core } = initProtectFixture());
|
|
@@ -38,7 +42,9 @@ describe('protect input-analysis http', function () {
|
|
|
38
42
|
|
|
39
43
|
it('should not be initialized after being required', function () {
|
|
40
44
|
expect(httpInstr.install).a('function');
|
|
41
|
-
expect(core.depHooks.install).not.to.have.been.called;
|
|
45
|
+
// the next two lines are effectively: expect(core.depHooks.install).not.to.have.been.called;
|
|
46
|
+
const depHooksInstall = core.Perf.all.get('agentify').get('agentify:@contrast/dep-hooks:install');
|
|
47
|
+
expect(depHooksInstall).equal(undefined);
|
|
42
48
|
expect(core.depHooks.resolve).not.to.have.been.called;
|
|
43
49
|
});
|
|
44
50
|
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
|
-
const { Event, StringPrototypeSubstr } = require('@contrast/common');
|
|
18
|
+
const { Event, primordials: { StringPrototypeSubstr } } = require('@contrast/common');
|
|
19
19
|
const address = require('ipaddr.js');
|
|
20
20
|
|
|
21
21
|
module.exports = (core) => {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
|
-
const { Event, StringPrototypeToLowerCase } = require('@contrast/common');
|
|
18
|
+
const { Event, primordials: { StringPrototypeToLowerCase, RegExpPrototypeTest } } = require('@contrast/common');
|
|
19
19
|
|
|
20
20
|
module.exports = (core) => {
|
|
21
21
|
const {
|
|
@@ -95,13 +95,13 @@ function buildVPEvaluators(virtualPatches, evaluatorsArray) {
|
|
|
95
95
|
function buildEvaluationCheck(evaluation) {
|
|
96
96
|
switch (evaluation) {
|
|
97
97
|
case 'MATCHES':
|
|
98
|
-
return (reqValue, matchedValue) => new RegExp(matchedValue, 'i')
|
|
98
|
+
return (reqValue, matchedValue) => RegExpPrototypeTest.call(new RegExp(matchedValue, 'i'), reqValue);
|
|
99
99
|
case 'EQUALS':
|
|
100
100
|
return (reqValue, matchedValue) => reqValue.toString() === matchedValue.toString();
|
|
101
101
|
case 'CONTAINS':
|
|
102
102
|
return (reqValue, matchedValue) => reqValue.includes(matchedValue);
|
|
103
103
|
case 'DOESNT_MATCH':
|
|
104
|
-
return (reqValue, matchedValue) => !new RegExp(matchedValue, 'i')
|
|
104
|
+
return (reqValue, matchedValue) => !RegExpPrototypeTest.call(new RegExp(matchedValue, 'i'), reqValue);
|
|
105
105
|
// This is a typo but it is how it's passed from ContrastUI
|
|
106
106
|
case 'DOESNT_EQUALS':
|
|
107
107
|
return (reqValue, matchedValue) => reqValue.toString() !== matchedValue.toString();
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
|
-
const { StringPrototypeToLowerCase, StringPrototypeSlice } = require('@contrast/common');
|
|
18
|
+
const { primordials: { StringPrototypeToLowerCase, StringPrototypeSlice } } = require('@contrast/common');
|
|
19
19
|
|
|
20
20
|
module.exports = function(core) {
|
|
21
21
|
const {
|
package/lib/policy.js
CHANGED
|
@@ -19,9 +19,12 @@ const {
|
|
|
19
19
|
Rule,
|
|
20
20
|
ProtectRuleMode,
|
|
21
21
|
Event,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
primordials: {
|
|
23
|
+
ArrayPrototypeJoin,
|
|
24
|
+
StringPrototypeToLowerCase,
|
|
25
|
+
StringPrototypeSplit,
|
|
26
|
+
RegExpPrototypeTest
|
|
27
|
+
}
|
|
25
28
|
} = require('@contrast/common');
|
|
26
29
|
const { ConfigSource } = require('@contrast/config');
|
|
27
30
|
|
|
@@ -90,7 +93,7 @@ module.exports = function (core) {
|
|
|
90
93
|
if (regExpNeeded) {
|
|
91
94
|
const rx = new RegExp(`^${ArrayPrototypeJoin.call(urls, '|')}$`);
|
|
92
95
|
|
|
93
|
-
return (uriPath) => rx ?
|
|
96
|
+
return (uriPath) => rx ? RegExpPrototypeTest.call(rx, uriPath) : false;
|
|
94
97
|
}
|
|
95
98
|
|
|
96
99
|
return (uriPath) => urls.some((url) => url === uriPath);
|
|
@@ -107,7 +110,7 @@ module.exports = function (core) {
|
|
|
107
110
|
function createInputNameMatcher(dtmInputName) {
|
|
108
111
|
if (regExpCheck(dtmInputName)) {
|
|
109
112
|
const rx = new RegExp(`^${dtmInputName}$`);
|
|
110
|
-
return (inputName) => rx ?
|
|
113
|
+
return (inputName) => rx ? RegExpPrototypeTest.call(rx, inputName) : false;
|
|
111
114
|
}
|
|
112
115
|
|
|
113
116
|
return (inputName) => inputName === dtmInputName;
|
|
@@ -21,7 +21,11 @@ const {
|
|
|
21
21
|
ProtectRuleMode: { OFF },
|
|
22
22
|
InputType,
|
|
23
23
|
traverseValues,
|
|
24
|
-
|
|
24
|
+
primordials: {
|
|
25
|
+
StringPrototypeReplace,
|
|
26
|
+
ArrayPrototypeSlice,
|
|
27
|
+
RegExpPrototypeTest
|
|
28
|
+
}
|
|
25
29
|
} = require('@contrast/common');
|
|
26
30
|
|
|
27
31
|
const {
|
|
@@ -166,7 +170,7 @@ function findBackdoorInjection(sourceContext, command) {
|
|
|
166
170
|
found = {
|
|
167
171
|
key,
|
|
168
172
|
inputType: path.length > 1 ? InputType.JSON_VALUE : inputType,
|
|
169
|
-
path:
|
|
173
|
+
path: ArrayPrototypeSlice.call(path, 0, -1),
|
|
170
174
|
value: command
|
|
171
175
|
};
|
|
172
176
|
|
|
@@ -195,6 +199,6 @@ function isBackdoorDetected(requestValue, command) {
|
|
|
195
199
|
return (
|
|
196
200
|
normalizedValue === normalizedCommand ||
|
|
197
201
|
(normalizedCommand.endsWith(normalizedValue) &&
|
|
198
|
-
|
|
202
|
+
RegExpPrototypeTest.call(SINK_EXPLOIT_PATTERN_START, normalizedCommand))
|
|
199
203
|
);
|
|
200
204
|
}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
'use strict';
|
|
16
16
|
|
|
17
|
-
const { StringPrototypeSubstr, StringPrototypeToLowerCase } = require('@contrast/common');
|
|
17
|
+
const { primordials: { StringPrototypeSubstr, StringPrototypeToLowerCase, RegExpPrototypeTest, RegExpPrototypeExec } } = require('@contrast/common');
|
|
18
18
|
|
|
19
19
|
const PROTOCOLS = {
|
|
20
20
|
FTP: 'FTP',
|
|
@@ -67,7 +67,7 @@ function isExternalEntity(str) {
|
|
|
67
67
|
if (str.startsWith(val)) return true;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
return
|
|
70
|
+
return RegExpPrototypeTest.call(FILE_PATTERN_WINDOWS, str);
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
/**
|
|
@@ -77,7 +77,7 @@ module.exports.findExternalEntities = function(xml = '') {
|
|
|
77
77
|
const entities = [];
|
|
78
78
|
let match;
|
|
79
79
|
|
|
80
|
-
while ((match =
|
|
80
|
+
while ((match = RegExpPrototypeExec.call(entityRegex, xml))) {
|
|
81
81
|
const {
|
|
82
82
|
groups: { type, uri1, uri2 }
|
|
83
83
|
} = match;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contrast/protect",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.44.0",
|
|
4
4
|
"description": "Contrast service providing framework-agnostic Protect support",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",
|
|
@@ -18,16 +18,16 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@contrast/agent-lib": "^7.0.1",
|
|
21
|
-
"@contrast/common": "1.
|
|
22
|
-
"@contrast/config": "1.
|
|
23
|
-
"@contrast/core": "1.
|
|
24
|
-
"@contrast/dep-hooks": "1.
|
|
25
|
-
"@contrast/esm-hooks": "2.
|
|
26
|
-
"@contrast/instrumentation": "1.
|
|
27
|
-
"@contrast/logger": "1.
|
|
28
|
-
"@contrast/patcher": "1.
|
|
29
|
-
"@contrast/rewriter": "1.
|
|
30
|
-
"@contrast/scopes": "1.
|
|
21
|
+
"@contrast/common": "1.26.0",
|
|
22
|
+
"@contrast/config": "1.34.0",
|
|
23
|
+
"@contrast/core": "1.38.0",
|
|
24
|
+
"@contrast/dep-hooks": "1.6.0",
|
|
25
|
+
"@contrast/esm-hooks": "2.12.0",
|
|
26
|
+
"@contrast/instrumentation": "1.16.0",
|
|
27
|
+
"@contrast/logger": "1.11.0",
|
|
28
|
+
"@contrast/patcher": "1.10.0",
|
|
29
|
+
"@contrast/rewriter": "1.14.0",
|
|
30
|
+
"@contrast/scopes": "1.7.0",
|
|
31
31
|
"ipaddr.js": "^2.0.1",
|
|
32
32
|
"semver": "^7.6.0"
|
|
33
33
|
},
|