@contrast/protect 1.39.0 → 1.40.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/lib/error-handlers/common-handler.test.js +52 -0
- package/lib/error-handlers/index.test.js +32 -0
- package/lib/error-handlers/init-domain.test.js +34 -0
- package/lib/error-handlers/install/express4.test.js +238 -0
- package/lib/error-handlers/install/fastify.test.js +130 -0
- package/lib/error-handlers/install/hapi.test.js +102 -0
- package/lib/error-handlers/install/koa2.test.js +83 -0
- package/lib/error-handlers/install/restify.test.js +57 -0
- package/lib/get-source-context.test.js +35 -0
- package/lib/hardening/handlers.test.js +89 -0
- package/lib/hardening/index.test.js +31 -0
- package/lib/hardening/install/node-serialize0.test.js +61 -0
- package/lib/index.test.js +53 -0
- package/lib/input-analysis/handlers.test.js +1604 -0
- package/lib/input-analysis/index.test.js +45 -0
- package/lib/input-analysis/install/body-parser1.test.js +134 -0
- package/lib/input-analysis/install/busboy1.test.js +81 -0
- package/lib/input-analysis/install/cookie-parser1.test.js +144 -0
- package/lib/input-analysis/install/express4.test.js +208 -0
- package/lib/input-analysis/install/fastify.test.js +96 -0
- package/lib/input-analysis/install/formidable1.test.js +114 -0
- package/lib/input-analysis/install/hapi.test.js +300 -0
- package/lib/input-analysis/install/http.test.js +264 -0
- package/lib/input-analysis/install/koa-body5.test.js +92 -0
- package/lib/input-analysis/install/koa-bodyparser4.test.js +92 -0
- package/lib/input-analysis/install/koa2.test.js +259 -0
- package/lib/input-analysis/install/multer1.test.js +209 -0
- package/lib/input-analysis/install/qs6.test.js +79 -0
- package/lib/input-analysis/install/restify.test.js +98 -0
- package/lib/input-analysis/install/universal-cookie4.test.js +70 -0
- package/lib/input-analysis/ip-analysis.test.js +71 -0
- package/lib/input-analysis/virtual-patches.test.js +106 -0
- package/lib/input-tracing/handlers/index.test.js +1236 -0
- package/lib/input-tracing/index.test.js +62 -0
- package/lib/input-tracing/install/child-process.test.js +133 -0
- package/lib/input-tracing/install/eval.test.js +78 -0
- package/lib/input-tracing/install/fs.test.js +108 -0
- package/lib/input-tracing/install/function.test.js +81 -0
- package/lib/input-tracing/install/http.test.js +85 -0
- package/lib/input-tracing/install/http2.test.js +83 -0
- package/lib/input-tracing/install/marsdb.test.js +126 -0
- package/lib/input-tracing/install/mongodb.test.js +282 -0
- package/lib/input-tracing/install/mssql.test.js +81 -0
- package/lib/input-tracing/install/mysql.test.js +108 -0
- package/lib/input-tracing/install/postgres.test.js +125 -0
- package/lib/input-tracing/install/sequelize.test.js +78 -0
- package/lib/input-tracing/install/spdy.test.js +76 -0
- package/lib/input-tracing/install/sqlite3.test.js +88 -0
- package/lib/input-tracing/install/vm.test.js +176 -0
- package/lib/make-response-blocker.test.js +99 -0
- package/lib/make-source-context.test.js +219 -0
- package/lib/policy.test.js +446 -0
- package/lib/semantic-analysis/handlers.test.js +379 -0
- package/lib/semantic-analysis/index.test.js +38 -0
- package/lib/semantic-analysis/install/libxmljs.test.js +156 -0
- package/lib/semantic-analysis/utils/xml-analysis.test.js +156 -0
- package/lib/throw-security-exception.test.js +37 -0
- package/package.json +5 -5
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const sinon = require('sinon');
|
|
4
|
+
const { expect } = require('chai');
|
|
5
|
+
const scopes = require('@contrast/scopes');
|
|
6
|
+
const patcher = require('@contrast/patcher');
|
|
7
|
+
const mocks = require('@contrast/test/mocks');
|
|
8
|
+
const universalCookieInstr = require('./universal-cookie4');
|
|
9
|
+
|
|
10
|
+
describe('protect input-analysis universal-cookie v4.x', function () {
|
|
11
|
+
let core, inputAnalysis, universalCookieMock, patchedUniversalCookie, cookie;
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
beforeEach(function () {
|
|
15
|
+
core = mocks.core();
|
|
16
|
+
core.logger = mocks.logger();
|
|
17
|
+
core.scopes = scopes(core);
|
|
18
|
+
core.protect = mocks.protect();
|
|
19
|
+
require('../../get-source-context')(core);
|
|
20
|
+
core.depHooks = mocks.depHooks();
|
|
21
|
+
core.patcher = patcher(core);
|
|
22
|
+
|
|
23
|
+
inputAnalysis = core.protect.inputAnalysis;
|
|
24
|
+
cookie = { parameter: 'parsed' };
|
|
25
|
+
universalCookieMock = {
|
|
26
|
+
parseCookies: (cookie) => cookie || {}
|
|
27
|
+
};
|
|
28
|
+
sinon.spy(core.patcher, 'patch');
|
|
29
|
+
|
|
30
|
+
universalCookieInstr(core).install();
|
|
31
|
+
patchedUniversalCookie = core.depHooks.resolve.yield(universalCookieMock)[0];
|
|
32
|
+
core.patcher.patch.resetHistory();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('calls patcher on the `.parseCookies` method', function () {
|
|
36
|
+
core.depHooks.resolve.yield(universalCookieMock);
|
|
37
|
+
|
|
38
|
+
expect(core.patcher.patch).to.have.been.calledOnce;
|
|
39
|
+
expect(core.patcher.patch).to.have.been.calledWithMatch(universalCookieMock, 'parseCookies', {
|
|
40
|
+
name: 'universal-cookie.utils',
|
|
41
|
+
patchType: 'protect-input-analysis',
|
|
42
|
+
post: sinon.match.func
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('calls `.handleCookies` when parsing is successful, in right context and with reqData.queries present', function () {
|
|
47
|
+
core.scopes.sources.run({ protect: {} }, () => {
|
|
48
|
+
patchedUniversalCookie.parseCookies(cookie);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
expect(inputAnalysis.handleCookies).to.have.been.calledOnce;
|
|
52
|
+
expect(inputAnalysis.handleCookies).to.have.been.calledWithMatch({ parsedCookies: cookie }, cookie);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('does not call `.handleCookies` when not in context', function () {
|
|
56
|
+
core.scopes.sources.run({}, () => {
|
|
57
|
+
patchedUniversalCookie.parseCookies(cookie);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
expect(inputAnalysis.handleCookies).not.to.have.been.called;
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('does not call `.handleCookies` when `universal-cookie` does not return a result', function () {
|
|
64
|
+
core.scopes.sources.run({ protect: {} }, () => {
|
|
65
|
+
patchedUniversalCookie.parseCookies(null);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
expect(inputAnalysis.handleCookies).not.to.have.been.called;
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { expect } = require('chai');
|
|
4
|
+
const sinon = require('sinon');
|
|
5
|
+
const mocks = require('@contrast/test/mocks');
|
|
6
|
+
const { Event } = require('@contrast/common');
|
|
7
|
+
const address = require('ipaddr.js');
|
|
8
|
+
|
|
9
|
+
describe('protect input-analysis ip-analysis', function () {
|
|
10
|
+
let core, serverUpdate, clock;
|
|
11
|
+
|
|
12
|
+
beforeEach(function () {
|
|
13
|
+
core = mocks.core();
|
|
14
|
+
core.protect = mocks.protect();
|
|
15
|
+
|
|
16
|
+
clock = sinon.useFakeTimers();
|
|
17
|
+
|
|
18
|
+
serverUpdate = {
|
|
19
|
+
protect: {
|
|
20
|
+
rules: {
|
|
21
|
+
ip_allowlist: [{ ip: '127.0.0.1', expires: 0 }, { ip: '1.2.3.4', expires: 50000 }],
|
|
22
|
+
ip_denylist: [{ ip: '192.168.1.0/12', expires: 0 }]
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
this.afterEach(function () {
|
|
29
|
+
clock.restore();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('stores the IP allow/deny lists', function () {
|
|
33
|
+
require('./ip-analysis')(core);
|
|
34
|
+
const { ipAllowlist, ipDenylist } = core.protect.inputAnalysis;
|
|
35
|
+
|
|
36
|
+
expect(ipAllowlist.length).to.equal(0);
|
|
37
|
+
expect(ipDenylist.length).to.equal(0);
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
core.messages.emit(Event.SERVER_SETTINGS_UPDATE, serverUpdate);
|
|
41
|
+
|
|
42
|
+
expect(ipAllowlist).to.deep.equal([
|
|
43
|
+
{
|
|
44
|
+
ip: '127.0.0.1',
|
|
45
|
+
expires: 0,
|
|
46
|
+
doesExpire: false,
|
|
47
|
+
expiresAt: undefined,
|
|
48
|
+
normalizedValue: '127.0.0.1',
|
|
49
|
+
cidr: undefined
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
ip: '1.2.3.4',
|
|
53
|
+
expires: 50000,
|
|
54
|
+
doesExpire: true,
|
|
55
|
+
expiresAt: 50000,
|
|
56
|
+
normalizedValue: '1.2.3.4',
|
|
57
|
+
cidr: undefined
|
|
58
|
+
}
|
|
59
|
+
]);
|
|
60
|
+
expect(ipDenylist).to.deep.equal([
|
|
61
|
+
{
|
|
62
|
+
ip: '192.168.1.0/12',
|
|
63
|
+
expires: 0,
|
|
64
|
+
doesExpire: false,
|
|
65
|
+
expiresAt: undefined,
|
|
66
|
+
normalizedValue: '192.168.1.0',
|
|
67
|
+
cidr: { range: address.parseCIDR('192.168.1.0/12'), kind: 'ipv4' }
|
|
68
|
+
}
|
|
69
|
+
]);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { expect } = require('chai');
|
|
4
|
+
const mocks = require('@contrast/test/mocks');
|
|
5
|
+
const { Event } = require('@contrast/common');
|
|
6
|
+
|
|
7
|
+
describe('protect input-analysis virtual-patches', function () {
|
|
8
|
+
let core, virtualPatches, positiveTestData, negativeTestData;
|
|
9
|
+
|
|
10
|
+
beforeEach(function () {
|
|
11
|
+
core = mocks.core();
|
|
12
|
+
core.protect = mocks.protect();
|
|
13
|
+
|
|
14
|
+
virtualPatches = [
|
|
15
|
+
{
|
|
16
|
+
headers: [{
|
|
17
|
+
evaluation: 'MATCHES',
|
|
18
|
+
name: 'Content-Type',
|
|
19
|
+
value: 'json'
|
|
20
|
+
}],
|
|
21
|
+
parameters: [{
|
|
22
|
+
evaluation: 'DOESNT_EQUALS',
|
|
23
|
+
name: 'sink',
|
|
24
|
+
value: 'safe'
|
|
25
|
+
}],
|
|
26
|
+
urls: [{
|
|
27
|
+
evaluation: 'CONTAINS',
|
|
28
|
+
value: 'database'
|
|
29
|
+
}],
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
headers: [{
|
|
33
|
+
evaluation: 'EQUALS',
|
|
34
|
+
name: 'malicious-header',
|
|
35
|
+
value: 'attack'
|
|
36
|
+
}],
|
|
37
|
+
parameters: [{
|
|
38
|
+
evaluation: 'DOESNT_CONTAIN',
|
|
39
|
+
name: 'sink',
|
|
40
|
+
value: 'safe'
|
|
41
|
+
}],
|
|
42
|
+
urls: [{
|
|
43
|
+
evaluation: 'DOESNT_MATCH',
|
|
44
|
+
value: 'public'
|
|
45
|
+
}],
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
urls: [{
|
|
49
|
+
evaluation: 'INVALID_EVALUATION',
|
|
50
|
+
value: 'invalid'
|
|
51
|
+
}]
|
|
52
|
+
}
|
|
53
|
+
];
|
|
54
|
+
positiveTestData = {
|
|
55
|
+
headers: [['content-type', 'application/json'], { 'malicious-header': 'attack' }],
|
|
56
|
+
parameters: [{ sink: 'unsafe' }, { sink: 'vulnerable' }],
|
|
57
|
+
urls: ['/api/v1/database', '/api/v1/private']
|
|
58
|
+
};
|
|
59
|
+
negativeTestData = {
|
|
60
|
+
headers: [['test-header', 'test'], ['safe-header', 'not-an-attack']],
|
|
61
|
+
parameters: [{ sink: 'safe' }, { sink: 'safe' }],
|
|
62
|
+
urls: ['/api/v1/about', '/api/v1/public']
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('builds the evaluators', function () {
|
|
67
|
+
require('./virtual-patches')(core);
|
|
68
|
+
const { virtualPatchesEvaluators } = core.protect.inputAnalysis;
|
|
69
|
+
|
|
70
|
+
expect(virtualPatchesEvaluators.length).to.equal(0);
|
|
71
|
+
|
|
72
|
+
core.messages.emit(Event.SERVER_SETTINGS_UPDATE, { protect: { 'virtual-patches': virtualPatches } });
|
|
73
|
+
|
|
74
|
+
expect(virtualPatchesEvaluators.length).to.equal(3);
|
|
75
|
+
expect(virtualPatchesEvaluators[0].size).to.equal(4);
|
|
76
|
+
expect(virtualPatchesEvaluators[1].size).to.equal(4);
|
|
77
|
+
expect(virtualPatchesEvaluators[2].size).to.equal(2);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('evaluates the patch conditions correctly', function () {
|
|
81
|
+
require('./virtual-patches')(core);
|
|
82
|
+
const { virtualPatchesEvaluators } = core.protect.inputAnalysis;
|
|
83
|
+
|
|
84
|
+
core.messages.emit(Event.SERVER_SETTINGS_UPDATE, { protect: { 'virtual-patches': virtualPatches } });
|
|
85
|
+
|
|
86
|
+
expect(virtualPatchesEvaluators.length).to.equal(3);
|
|
87
|
+
virtualPatchesEvaluators.forEach((evaluators, index) => {
|
|
88
|
+
const headersEvaluator = evaluators.get('HEADERS');
|
|
89
|
+
const parametersEvaluator = evaluators.get('PARAMETERS');
|
|
90
|
+
const urlsEvaluators = evaluators.get('URLS');
|
|
91
|
+
|
|
92
|
+
if (index !== 2) {
|
|
93
|
+
expect(headersEvaluator(positiveTestData.headers[index])).to.be.true;
|
|
94
|
+
expect(headersEvaluator(negativeTestData.headers[index])).to.be.false;
|
|
95
|
+
expect(parametersEvaluator(positiveTestData.parameters[index])).to.be.true;
|
|
96
|
+
expect(parametersEvaluator(negativeTestData.parameters[index])).to.be.false;
|
|
97
|
+
expect(urlsEvaluators(positiveTestData.urls[index])).to.be.true;
|
|
98
|
+
expect(urlsEvaluators(negativeTestData.urls[index])).to.be.false;
|
|
99
|
+
} else {
|
|
100
|
+
expect(headersEvaluator).to.be.undefined;
|
|
101
|
+
expect(parametersEvaluator).to.be.undefined;
|
|
102
|
+
expect(urlsEvaluators(positiveTestData.urls[0])).to.be.false;
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
});
|