@contrast/protect 1.54.0 → 1.54.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.
Files changed (58) hide show
  1. package/package.json +14 -11
  2. package/lib/error-handlers/common-handler.test.js +0 -52
  3. package/lib/error-handlers/index.test.js +0 -32
  4. package/lib/error-handlers/init-domain.test.js +0 -22
  5. package/lib/error-handlers/install/express.test.js +0 -290
  6. package/lib/error-handlers/install/fastify.test.js +0 -130
  7. package/lib/error-handlers/install/hapi.test.js +0 -102
  8. package/lib/error-handlers/install/koa2.test.js +0 -83
  9. package/lib/error-handlers/install/restify.test.js +0 -57
  10. package/lib/get-source-context.test.js +0 -35
  11. package/lib/hardening/handlers.test.js +0 -89
  12. package/lib/hardening/index.test.js +0 -31
  13. package/lib/hardening/install/node-serialize0.test.js +0 -58
  14. package/lib/index.test.js +0 -53
  15. package/lib/input-analysis/handlers.test.js +0 -1604
  16. package/lib/input-analysis/index.test.js +0 -45
  17. package/lib/input-analysis/install/body-parser1.test.js +0 -134
  18. package/lib/input-analysis/install/busboy1.test.js +0 -81
  19. package/lib/input-analysis/install/cookie-parser1.test.js +0 -144
  20. package/lib/input-analysis/install/express.test.js +0 -241
  21. package/lib/input-analysis/install/fastify.test.js +0 -96
  22. package/lib/input-analysis/install/formidable1.test.js +0 -114
  23. package/lib/input-analysis/install/hapi.test.js +0 -292
  24. package/lib/input-analysis/install/http.test.js +0 -270
  25. package/lib/input-analysis/install/koa-body5.test.js +0 -92
  26. package/lib/input-analysis/install/koa-bodyparser4.test.js +0 -92
  27. package/lib/input-analysis/install/koa2.test.js +0 -259
  28. package/lib/input-analysis/install/multer1.test.js +0 -209
  29. package/lib/input-analysis/install/qs6.test.js +0 -79
  30. package/lib/input-analysis/install/restify.test.js +0 -98
  31. package/lib/input-analysis/install/universal-cookie4.test.js +0 -70
  32. package/lib/input-analysis/ip-analysis.test.js +0 -71
  33. package/lib/input-analysis/virtual-patches.test.js +0 -106
  34. package/lib/input-tracing/handlers/index.test.js +0 -1237
  35. package/lib/input-tracing/index.test.js +0 -62
  36. package/lib/input-tracing/install/child-process.test.js +0 -133
  37. package/lib/input-tracing/install/eval.test.js +0 -78
  38. package/lib/input-tracing/install/fs.test.js +0 -108
  39. package/lib/input-tracing/install/function.test.js +0 -81
  40. package/lib/input-tracing/install/http.test.js +0 -85
  41. package/lib/input-tracing/install/http2.test.js +0 -83
  42. package/lib/input-tracing/install/marsdb.test.js +0 -126
  43. package/lib/input-tracing/install/mongodb.test.js +0 -280
  44. package/lib/input-tracing/install/mssql.test.js +0 -81
  45. package/lib/input-tracing/install/mysql.test.js +0 -108
  46. package/lib/input-tracing/install/postgres.test.js +0 -117
  47. package/lib/input-tracing/install/sequelize.test.js +0 -78
  48. package/lib/input-tracing/install/spdy.test.js +0 -76
  49. package/lib/input-tracing/install/sqlite3.test.js +0 -88
  50. package/lib/input-tracing/install/vm.test.js +0 -176
  51. package/lib/make-response-blocker.test.js +0 -99
  52. package/lib/make-source-context.test.js +0 -219
  53. package/lib/policy.test.js +0 -446
  54. package/lib/semantic-analysis/handlers.test.js +0 -379
  55. package/lib/semantic-analysis/index.test.js +0 -38
  56. package/lib/semantic-analysis/install/libxmljs.test.js +0 -156
  57. package/lib/semantic-analysis/utils/xml-analysis.test.js +0 -156
  58. package/lib/throw-security-exception.test.js +0 -37
@@ -1,96 +0,0 @@
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 SecurityException = require('../../security-exception');
9
- const secEx = SecurityException.create();
10
- const fastifyInstr = require('./fastify');
11
-
12
- describe('protect input-analysis fastify v3.x', function () {
13
- let core, inputAnalysis, fastify, serverMock, reqMock, resMock, doneMock;
14
-
15
- beforeEach(function () {
16
- core = mocks.core();
17
- core.logger = mocks.logger();
18
- core.scopes = scopes(core);
19
- core.protect = mocks.protect();
20
- require('../../get-source-context')(core);
21
- core.depHooks = mocks.depHooks();
22
- core.patcher = patcher(core);
23
-
24
- reqMock = {
25
- query: { foo: 'bar' },
26
- cookies: { foo: 'bar' },
27
- params: { foo: 'bar' },
28
- body: { foo: 'bar' },
29
- };
30
- resMock = {};
31
- doneMock = sinon.stub();
32
- serverMock = {
33
- addHook: sinon.stub().yields(reqMock, resMock, doneMock),
34
- };
35
-
36
- const fastifyOrig = () => serverMock;
37
- core.depHooks.resolve.callsFake(function (desc, cb) {
38
- fastify = cb(fastifyOrig);
39
- });
40
-
41
- inputAnalysis = core.protect.inputAnalysis;
42
- fastifyInstr(core).install();
43
- });
44
-
45
- describe('preValidationHook', function () {
46
- it('adds hook and calls appropriate analysis handlers', function () {
47
- core.scopes.sources.run({ protect: {} }, () => {
48
- fastify();
49
- });
50
-
51
- expect(serverMock.addHook).to.have.been.called;
52
- expect(doneMock).to.have.been.called;
53
- expect(core.logger.debug).not.to.have.been.called;
54
-
55
- expect(inputAnalysis.handleQueryParams).to.have.been.called;
56
- expect(inputAnalysis.handleUrlParams).to.have.been.called;
57
- expect(inputAnalysis.handleCookies).to.have.been.called;
58
- expect(inputAnalysis.handleParsedBody).to.have.been.called;
59
- });
60
-
61
- it('input analysis does not occur if there is no protect source context', function () {
62
- fastify();
63
- expect(doneMock).to.have.been.called;
64
-
65
- expect(inputAnalysis.handleQueryParams).not.to.have.been.called;
66
- expect(inputAnalysis.handleUrlParams).not.to.have.been.called;
67
- expect(inputAnalysis.handleCookies).not.to.have.been.called;
68
- expect(inputAnalysis.handleParsedBody).not.to.have.been.called;
69
- });
70
-
71
- it('handles a case with SecurityException from the input-analysis', function () {
72
- inputAnalysis.handleQueryParams.throws(secEx);
73
- core.scopes.sources.run({ protect: {} }, () => {
74
- fastify();
75
- });
76
-
77
- expect(doneMock).to.have.been.calledOnceWith(secEx);
78
- });
79
-
80
- it('handles a case with a normal error in the input analysis', function () {
81
- const err = new Error('Input Analysis Error');
82
-
83
- inputAnalysis.handleQueryParams.throws(err);
84
- core.scopes.sources.run({ protect: {} }, () => {
85
- fastify();
86
- });
87
-
88
- expect(core.logger.error).to.have.been.calledWith(
89
- { err, funcKey: 'protect-input-analysis:fastify.build' },
90
- 'Unexpected error during input analysis'
91
- );
92
- expect(doneMock).to.have.been.calledOnce;
93
- expect(doneMock).not.to.have.been.calledWith(err);
94
- });
95
- });
96
- });
@@ -1,114 +0,0 @@
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 formidableInstr = require('./formidable1');
9
-
10
- describe('protect input-analysis formidable v1.x', function () {
11
- let core, inputAnalysis, parseMock, patchedParse, req, cbStub;
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
- req = { fields: { parameter: 'parsed' }, files: { fileField: { name: 'some-file' } } };
25
- parseMock = (req, cb) => {
26
- if (typeof cb === 'function') {
27
- cb(null, req.fields, req.files);
28
- }
29
- };
30
- cbStub = sinon.stub();
31
- sinon.spy(core.patcher, 'patch');
32
-
33
- formidableInstr(core).install();
34
- patchedParse = core.depHooks.resolve.yield({ IncomingForm: { prototype: { parse: parseMock } } })[0].IncomingForm.prototype.parse;
35
- core.patcher.patch.resetHistory();
36
- });
37
-
38
- it('calls patcher on the `.parse` method', function () {
39
- core.depHooks.resolve.yield({ IncomingForm: { prototype: { parse: parseMock } } });
40
-
41
- expect(core.patcher.patch).to.have.been.calledOnce;
42
- expect(core.patcher.patch).to.have.been.calledWithMatch(sinon.match.func, {
43
- name: 'Formidable.IncomingForm.prototype.parse',
44
- patchType: 'protect-input-analysis',
45
- pre: sinon.match.func
46
- });
47
- });
48
-
49
- it('calls `.handleParsedBody` and `handleFileUploadName` when parsing is successful and in right context', function () {
50
- core.scopes.sources.run({ protect: {} }, () => {
51
- patchedParse(req, cbStub);
52
- });
53
-
54
- expect(cbStub).to.have.been.calledOnce;
55
- expect(inputAnalysis.handleParsedBody).to.have.been.calledOnce;
56
- expect(inputAnalysis.handleParsedBody).to.have.been.calledWithMatch({ parsedBody: req.fields }, req.fields);
57
- expect(inputAnalysis.handleFileUploadName).to.have.been.calledOnce;
58
- expect(inputAnalysis.handleFileUploadName).to.have.been.calledWithMatch({ parsedBody: req.fields }, ['some-file']);
59
- });
60
-
61
-
62
- it('calls `handleFileUploadName` when parsing is successful with multiple files and in right context', function () {
63
- req.files = { filesField: [{ name: 'some-file-1' }, { name: 'some-file-2' }] };
64
- core.scopes.sources.run({ protect: {} }, () => {
65
- patchedParse(req, cbStub);
66
- });
67
-
68
- expect(inputAnalysis.handleFileUploadName).to.have.been.calledOnce;
69
- expect(inputAnalysis.handleFileUploadName).to.have.been.calledWithMatch({ parsedBody: req.fields }, ['some-file-1', 'some-file-2']);
70
- });
71
-
72
- it('calls `.handleParsedBody` when parsing is successful and in right context, but there are no files', function () {
73
- req.files = null;
74
- core.scopes.sources.run({ protect: {} }, () => {
75
- patchedParse(req, cbStub);
76
- });
77
-
78
- expect(cbStub).to.have.been.calledOnce;
79
- expect(inputAnalysis.handleParsedBody).to.have.been.calledOnce;
80
- expect(inputAnalysis.handleParsedBody).to.have.been.calledWithMatch({ parsedBody: req.fields }, req.fields);
81
- expect(core.logger.debug).not.to.have.been.called;
82
- });
83
-
84
- it('does not call `.handleParsedBody` when not in context', function () {
85
- core.scopes.sources.run({}, () => {
86
- patchedParse(req, cbStub);
87
- });
88
-
89
- expect(inputAnalysis.handleParsedBody).not.to.have.been.called;
90
- expect(cbStub).to.have.been.calledOnce;
91
- });
92
-
93
- it('does not call `.handleParsedBody` when `formidable` there is a result, but only files are uploaded', function () {
94
- req.fields = null;
95
- core.scopes.sources.run({ protect: {} }, () => {
96
- patchedParse(req, cbStub);
97
- });
98
-
99
- expect(inputAnalysis.handleParsedBody).not.to.have.been.called;
100
- expect(inputAnalysis.handleFileUploadName).to.have.been.calledOnce;
101
- expect(inputAnalysis.handleFileUploadName).to.have.been.calledWithMatch({}, ['some-file']);
102
- expect(cbStub).to.have.been.calledOnce;
103
- });
104
-
105
- it('does not call `.handleParsedBody` when `formidable` does not return a result', function () {
106
- core.scopes.sources.run({ protect: {} }, () => {
107
- patchedParse({}, cbStub);
108
- });
109
-
110
- expect(inputAnalysis.handleParsedBody).not.to.have.been.called;
111
- expect(core.logger.debug).not.to.have.been.called;
112
- expect(cbStub).to.have.been.calledOnce;
113
- });
114
- });
@@ -1,292 +0,0 @@
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 { create, isSecurityException } = require('../../security-exception');
9
-
10
- describe('protect input-analysis hapi', function () {
11
- let core,
12
- hapiSources,
13
- store,
14
- inputAnalysis;
15
-
16
- const Hapi = { name: 'hapi' };
17
- const HapiHapi = { name: '@hapi/hapi' };
18
- const HapiPez = { name: '@hapi/pez' };
19
-
20
- beforeEach(function () {
21
- core = mocks.core();
22
- core.config = mocks.config();
23
- core.logger = mocks.logger();
24
- core.scopes = scopes(core);
25
- core.protect = mocks.protect();
26
- require('../../get-source-context')(core);
27
- core.depHooks = mocks.depHooks();
28
- core.patcher = patcher(core);
29
-
30
- inputAnalysis = core.protect.inputAnalysis;
31
- sinon.spy(core.patcher, 'patch');
32
- store = {
33
- protect: {
34
- block: sinon.stub(),
35
- securityException: ['block', 'cmd-injection']
36
- }
37
- };
38
-
39
- Hapi.server = function hapi(server) {
40
- return server;
41
- };
42
- HapiHapi.server = function hapiHapi(server) {
43
- return server;
44
- };
45
- HapiPez.Dispenser = function () { };
46
- HapiPez.Dispenser.prototype.emit = function () { };
47
-
48
- core.depHooks.resolve.withArgs(sinon.match({ name: Hapi.name })).yields(Hapi);
49
- core.depHooks.resolve.withArgs(sinon.match({ name: HapiHapi.name })).yields(HapiHapi);
50
- core.depHooks.resolve.withArgs(sinon.match({ name: HapiPez.name })).yields(HapiPez);
51
-
52
- hapiSources = require('./hapi')(core);
53
- hapiSources.install();
54
- });
55
-
56
- [Hapi, HapiHapi].forEach((module) => {
57
- it(`skip instrumentation if server is missing - ${module.name}`, function () {
58
- const { server } = module;
59
-
60
- core.scopes.sources.run(store, () => {
61
- server();
62
- expect(core.logger.error).to.have.been.calledWith(
63
- { funcKey: 'protect-input-analysis:hapi.server' },
64
- 'Hapi Server is called but there is no server instance!'
65
- );
66
- });
67
- });
68
- });
69
-
70
- [Hapi, HapiHapi].forEach((module) => {
71
- it(`should log onPreStart hapi version - ${module.name}`, function () {
72
- const { server } = module;
73
- const serverInstance = {
74
- ext: sinon.stub(),
75
- };
76
-
77
- serverInstance.ext.withArgs('onPreStart', sinon.match.func).callsFake((string, method) => {
78
- method({ version: '4.0.0' });
79
- });
80
-
81
- core.scopes.sources.run(store, () => {
82
- server(serverInstance);
83
- expect(core.logger.debug).to.have.been.calledWith('hapi version %s', '4.0.0');
84
- });
85
- });
86
- });
87
-
88
- [Hapi, HapiHapi].forEach((module) => {
89
- it(`should handle url params, state (cookies), payload/body, query - ${module.name}`, function () {
90
- const { server } = module;
91
- const serverInstance = {
92
- ext: sinon.stub(),
93
- };
94
-
95
- const params = { userId: 1 };
96
- const state = { auth: 'vasko jabata' };
97
- const payload = { name: 'vasko jabata' };
98
- const query = { name: 'vasko jabata' };
99
-
100
- serverInstance.ext.withArgs('onPreHandler', sinon.match.func).callsFake((string, method) => {
101
- method({
102
- params,
103
- state,
104
- payload,
105
- query,
106
- }, {
107
- continue: () => { }
108
- });
109
- });
110
-
111
- core.scopes.sources.run(store, () => {
112
- server(serverInstance);
113
-
114
- expect(store.protect.parsedParams).to.eql(params);
115
- expect(store.protect.parsedCookies).to.eql(state);
116
- expect(store.protect.parsedBody).to.eql(payload);
117
- expect(store.protect.parsedQuery).to.eql(query);
118
- expect(core.protect.inputAnalysis.handleUrlParams).to.have.been.calledWith(sinon.match.object, params);
119
- expect(core.protect.inputAnalysis.handleCookies).to.have.been.calledWith(sinon.match.object, state);
120
- expect(core.protect.inputAnalysis.handleParsedBody).to.have.been.calledWith(sinon.match.object, payload);
121
- expect(core.protect.inputAnalysis.handleQueryParams).to.have.been.calledWith(sinon.match.object, query);
122
- });
123
- });
124
- });
125
-
126
- [Hapi, HapiHapi].forEach((module) => {
127
- it(`error handling - ${module.name}`, function () {
128
- const err = new Error('error');
129
-
130
- const { server } = module;
131
- const serverInstance = {
132
- ext: sinon.stub(),
133
- };
134
-
135
- const params = { userId: 1 };
136
-
137
- serverInstance.ext.withArgs('onPreHandler', sinon.match.func).callsFake((string, method) => {
138
- method({
139
- params,
140
- }, {
141
- continue: () => { }
142
- });
143
- });
144
-
145
- core.protect.inputAnalysis.handleUrlParams.callsFake(() => {
146
- throw err;
147
- });
148
-
149
- core.scopes.sources.run(store, () => {
150
- server(serverInstance);
151
- expect(core.logger.error).to.have.been.calledWith(
152
- { err, funcKey: 'protect-input-analysis:hapi.server' },
153
- 'Unexpected error during input analysis',
154
- );
155
- });
156
- });
157
-
158
- it(`should throw SecurityException - ${module.name}`, function () {
159
- const error = create();
160
-
161
- const { server } = module;
162
- const serverInstance = {
163
- ext: sinon.stub(),
164
- };
165
-
166
- const params = { userId: 1 };
167
-
168
- serverInstance.ext.withArgs('onPreHandler', sinon.match.func).callsFake((string, method) => {
169
- method({
170
- params,
171
- }, {
172
- continue: () => { }
173
- });
174
- });
175
-
176
- core.protect.inputAnalysis.handleUrlParams.callsFake(() => {
177
- throw error;
178
- });
179
-
180
- core.scopes.sources.run(store, () => {
181
- try {
182
- server(serverInstance);
183
- } catch (error) {
184
- expect(isSecurityException(error)).to.be.true;
185
- }
186
- });
187
- });
188
- });
189
-
190
- [Hapi, HapiHapi].forEach((module) => {
191
- it(`empty request - ${module.name}`, function () {
192
- const { server } = module;
193
- const serverInstance = {
194
- ext: sinon.stub(),
195
- };
196
-
197
- const continueFunction = () => ({});
198
- let result;
199
- serverInstance.ext.withArgs('onPreHandler', sinon.match.func).callsFake((string, method) => {
200
- result = method({}, {
201
- continue: continueFunction
202
- });
203
- });
204
-
205
- core.scopes.sources.run(store, () => {
206
- server(serverInstance);
207
- expect(result).to.eql(continueFunction);
208
- });
209
- });
210
-
211
- it(`empty sourceContext - ${module.name}`, function () {
212
- const { server } = module;
213
- const serverInstance = {
214
- ext: sinon.stub(),
215
- };
216
-
217
- const continueFunction = () => ({});
218
- let result;
219
- serverInstance.ext.withArgs('onPreHandler', sinon.match.func).callsFake((string, method) => {
220
- result = method({}, {
221
- continue: continueFunction
222
- });
223
- });
224
-
225
- core.scopes.sources.run({}, () => {
226
- server(serverInstance);
227
- expect(result).to.eql(continueFunction);
228
- });
229
- });
230
- });
231
-
232
- describe('hapi/pez', function () {
233
- it('works', function () {
234
- HapiPez.Dispenser.prototype.emit();
235
- });
236
- it('calls patcher on the `.emit` method', function () {
237
-
238
- expect(core.patcher.patch).to.have.callCount(3);
239
- expect(core.patcher.patch).to.have.been.calledWithMatch(Hapi, 'server', {
240
- name: 'hapi.server',
241
- patchType: 'protect-input-analysis',
242
- post: sinon.match.func
243
- });
244
- expect(core.patcher.patch).to.have.been.calledWithMatch(HapiHapi, 'server', {
245
- name: 'hapi.server',
246
- patchType: 'protect-input-analysis',
247
- post: sinon.match.func
248
- });
249
- expect(core.patcher.patch).to.have.been.calledWithMatch(HapiPez.Dispenser.prototype, 'emit', {
250
- name: 'Pez.Dispenser.prototype.emit',
251
- patchType: 'protect-input-analysis',
252
- pre: sinon.match.func
253
- });
254
- });
255
-
256
- it('calls `.handleFileUploadName` when there is a multipart file and it is in right context', function () {
257
- core.scopes.sources.run({ protect: {} }, () => {
258
- HapiPez.Dispenser.prototype.emit('part', { filename: 'filename' });
259
- });
260
-
261
- expect(inputAnalysis.handleFileUploadName).to.have.been.calledOnce;
262
- expect(inputAnalysis.handleFileUploadName).to.have.been.calledWithMatch({}, ['filename']);
263
- });
264
-
265
-
266
- it('does not call `.handleFileUploadName` when not in context', function () {
267
- core.scopes.sources.run({}, () => {
268
- HapiPez.Dispenser.prototype.emit('part', { filename: 'filename' });
269
- });
270
-
271
- expect(inputAnalysis.handleFileUploadName).not.to.have.been.called;
272
- });
273
-
274
- it('does not call `.handleFileUploadName` when `.emit` is not called with `part` event', function () {
275
- core.scopes.sources.run({ protect: {} }, () => {
276
- HapiPez.Dispenser.prototype.emit('not-part', { filename: 'filename' });
277
- });
278
-
279
- expect(inputAnalysis.handleParsedBody).not.to.have.been.called;
280
- expect(core.logger.debug).not.to.have.been.called;
281
- });
282
-
283
- it('does not call `.handleFileUploadName` when `.emit` call does not contain a filename', function () {
284
- core.scopes.sources.run({ protect: {} }, () => {
285
- HapiPez.Dispenser.prototype.emit('part', { filename: null });
286
- });
287
-
288
- expect(inputAnalysis.handleParsedBody).not.to.have.been.called;
289
- expect(core.logger.debug).not.to.have.been.called;
290
- });
291
- });
292
- });