@contrast/protect 1.38.0 → 1.40.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.
Files changed (58) hide show
  1. package/lib/error-handlers/common-handler.test.js +52 -0
  2. package/lib/error-handlers/index.test.js +32 -0
  3. package/lib/error-handlers/init-domain.test.js +34 -0
  4. package/lib/error-handlers/install/express4.test.js +238 -0
  5. package/lib/error-handlers/install/fastify.test.js +130 -0
  6. package/lib/error-handlers/install/hapi.test.js +102 -0
  7. package/lib/error-handlers/install/koa2.test.js +83 -0
  8. package/lib/error-handlers/install/restify.test.js +57 -0
  9. package/lib/get-source-context.test.js +35 -0
  10. package/lib/hardening/handlers.test.js +89 -0
  11. package/lib/hardening/index.test.js +31 -0
  12. package/lib/hardening/install/node-serialize0.test.js +61 -0
  13. package/lib/index.test.js +53 -0
  14. package/lib/input-analysis/handlers.test.js +1604 -0
  15. package/lib/input-analysis/index.test.js +45 -0
  16. package/lib/input-analysis/install/body-parser1.test.js +134 -0
  17. package/lib/input-analysis/install/busboy1.test.js +81 -0
  18. package/lib/input-analysis/install/cookie-parser1.test.js +144 -0
  19. package/lib/input-analysis/install/express4.test.js +208 -0
  20. package/lib/input-analysis/install/fastify.test.js +96 -0
  21. package/lib/input-analysis/install/formidable1.test.js +114 -0
  22. package/lib/input-analysis/install/hapi.test.js +300 -0
  23. package/lib/input-analysis/install/http.test.js +264 -0
  24. package/lib/input-analysis/install/koa-body5.test.js +92 -0
  25. package/lib/input-analysis/install/koa-bodyparser4.test.js +92 -0
  26. package/lib/input-analysis/install/koa2.test.js +259 -0
  27. package/lib/input-analysis/install/multer1.test.js +209 -0
  28. package/lib/input-analysis/install/qs6.test.js +79 -0
  29. package/lib/input-analysis/install/restify.test.js +98 -0
  30. package/lib/input-analysis/install/universal-cookie4.test.js +70 -0
  31. package/lib/input-analysis/ip-analysis.test.js +71 -0
  32. package/lib/input-analysis/virtual-patches.test.js +106 -0
  33. package/lib/input-tracing/handlers/index.test.js +1236 -0
  34. package/lib/input-tracing/index.test.js +62 -0
  35. package/lib/input-tracing/install/child-process.test.js +133 -0
  36. package/lib/input-tracing/install/eval.test.js +78 -0
  37. package/lib/input-tracing/install/fs.test.js +108 -0
  38. package/lib/input-tracing/install/function.test.js +81 -0
  39. package/lib/input-tracing/install/http.test.js +85 -0
  40. package/lib/input-tracing/install/http2.test.js +83 -0
  41. package/lib/input-tracing/install/marsdb.test.js +126 -0
  42. package/lib/input-tracing/install/mongodb.test.js +282 -0
  43. package/lib/input-tracing/install/mssql.test.js +81 -0
  44. package/lib/input-tracing/install/mysql.test.js +108 -0
  45. package/lib/input-tracing/install/postgres.test.js +125 -0
  46. package/lib/input-tracing/install/sequelize.test.js +78 -0
  47. package/lib/input-tracing/install/spdy.test.js +76 -0
  48. package/lib/input-tracing/install/sqlite3.test.js +88 -0
  49. package/lib/input-tracing/install/vm.test.js +176 -0
  50. package/lib/make-response-blocker.test.js +99 -0
  51. package/lib/make-source-context.test.js +219 -0
  52. package/lib/policy.test.js +446 -0
  53. package/lib/semantic-analysis/handlers.test.js +379 -0
  54. package/lib/semantic-analysis/index.test.js +38 -0
  55. package/lib/semantic-analysis/install/libxmljs.test.js +156 -0
  56. package/lib/semantic-analysis/utils/xml-analysis.test.js +156 -0
  57. package/lib/throw-security-exception.test.js +37 -0
  58. 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
+ });