@contrast/assess 1.29.1 → 1.30.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.
|
@@ -24,18 +24,30 @@ const { InstrumentationType: { RULE } } = require('../../constants');
|
|
|
24
24
|
const { PATCH_TYPE: patchType } = require('../common');
|
|
25
25
|
|
|
26
26
|
const SAFE_HASH_ALGORITHMS = new Set([
|
|
27
|
-
|
|
28
|
-
'
|
|
29
|
-
'
|
|
30
|
-
'
|
|
31
|
-
'RSA-SHA512',
|
|
27
|
+
// SHA224
|
|
28
|
+
'rsa-sha224',
|
|
29
|
+
'sha-224',
|
|
30
|
+
'sha2-224',
|
|
32
31
|
'sha224',
|
|
33
|
-
'
|
|
32
|
+
'sha224withrsaencryption',
|
|
33
|
+
// SHA256
|
|
34
|
+
'rsa-sha256',
|
|
35
|
+
'sha-256',
|
|
36
|
+
'sha2-256',
|
|
34
37
|
'sha256',
|
|
35
|
-
'
|
|
38
|
+
'sha256withrsaencryption',
|
|
39
|
+
// SHA384
|
|
40
|
+
'rsa-sha384',
|
|
41
|
+
'sha-384',
|
|
42
|
+
'sha2-384',
|
|
36
43
|
'sha384',
|
|
37
|
-
'
|
|
38
|
-
|
|
44
|
+
'sha384withrsaencryption',
|
|
45
|
+
// SHA512
|
|
46
|
+
'rsa-sha512',
|
|
47
|
+
'sha-512',
|
|
48
|
+
'sha2-512',
|
|
49
|
+
'sha512',
|
|
50
|
+
'sha512withrsaencryption',
|
|
39
51
|
]);
|
|
40
52
|
const SAFE_HASH_LIBS = ['etag', 'browserify', 'deps-sort'];
|
|
41
53
|
const SAFE_CIPHER_ALGORITHM_PREFIXES = ['des-ede', 'id-aes', 'aes', 'rsa'];
|
|
@@ -53,7 +65,6 @@ module.exports = function (core) {
|
|
|
53
65
|
logger,
|
|
54
66
|
patcher,
|
|
55
67
|
assess: {
|
|
56
|
-
inspect, // todo: remove
|
|
57
68
|
eventFactory,
|
|
58
69
|
cryptoAnalysis,
|
|
59
70
|
getSourceContext,
|
|
@@ -68,16 +79,14 @@ module.exports = function (core) {
|
|
|
68
79
|
patchType,
|
|
69
80
|
post(data) {
|
|
70
81
|
const [alg] = data.args;
|
|
82
|
+
if (!isString(alg) || !getSourceContext(RULE, Rule.CRYPTO_BAD_MAC)) return;
|
|
71
83
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
!getSourceContext(RULE, Rule.CRYPTO_BAD_MAC) ||
|
|
75
|
-
SAFE_HASH_ALGORITHMS.has(alg)
|
|
76
|
-
) return;
|
|
84
|
+
const algLower = StringPrototypeToLowerCase.call(alg);
|
|
85
|
+
if (SAFE_HASH_ALGORITHMS.has(algLower)) return;
|
|
77
86
|
|
|
78
87
|
const event = eventFactory.createCryptoAnalysisEvent({
|
|
79
88
|
args: [{ tracked: false, value: alg }],
|
|
80
|
-
context: `crypto.createHash(${
|
|
89
|
+
context: `crypto.createHash(${algLower})`,
|
|
81
90
|
methodName: 'createHash',
|
|
82
91
|
moduleName: 'crypto',
|
|
83
92
|
name: 'crypto.createHash',
|
|
@@ -130,7 +139,7 @@ module.exports = function (core) {
|
|
|
130
139
|
|
|
131
140
|
const event = eventFactory.createCryptoAnalysisEvent({
|
|
132
141
|
args: [{ tracked: false, value: alg }],
|
|
133
|
-
context: `crypto.${method}(${
|
|
142
|
+
context: `crypto.${method}(${algLower})`,
|
|
134
143
|
methodName: method,
|
|
135
144
|
moduleName: 'crypto',
|
|
136
145
|
name: `crypto.${method}`,
|
|
@@ -77,11 +77,13 @@ module.exports = function(core) {
|
|
|
77
77
|
WEAK_URL_ENCODED,
|
|
78
78
|
];
|
|
79
79
|
|
|
80
|
-
const preHook = (
|
|
80
|
+
const preHook = (moduleName, responseName, method) => ({ args, obj: response, result, hooked, orig }) => {
|
|
81
|
+
const methodName = `${responseName + (moduleName !== 'spdy' ? '.prototype' : '')}.${method}`;
|
|
82
|
+
const name = `${moduleName}.${methodName}`;
|
|
81
83
|
const sourceContext = getSourceContext(RULE, ruleId);
|
|
82
84
|
if (!sourceContext) return;
|
|
83
85
|
|
|
84
|
-
const payload =
|
|
86
|
+
const payload = args[0];
|
|
85
87
|
if (!payload) return;
|
|
86
88
|
|
|
87
89
|
const strInfo = tracker.getData(payload);
|
|
@@ -90,6 +92,7 @@ module.exports = function(core) {
|
|
|
90
92
|
const { contentType } = sourceContext.responseData;
|
|
91
93
|
if (contentType && isSafeContentType(contentType)) return;
|
|
92
94
|
|
|
95
|
+
if (moduleName === 'spdy') response.spdyStream.once('finish', () => response.emit('finish'));
|
|
93
96
|
if (isVulnerable(UNTRUSTED, safeTags, strInfo.tags)) {
|
|
94
97
|
const event = createSinkEvent({
|
|
95
98
|
args: [{
|
|
@@ -99,20 +102,20 @@ module.exports = function(core) {
|
|
|
99
102
|
context: `res.${method}('${strInfo.value}')`,
|
|
100
103
|
history: [strInfo],
|
|
101
104
|
name,
|
|
102
|
-
moduleName
|
|
103
|
-
methodName
|
|
105
|
+
moduleName,
|
|
106
|
+
methodName,
|
|
104
107
|
object: {
|
|
105
108
|
tracked: false,
|
|
106
|
-
value:
|
|
109
|
+
value: `${moduleName}.${responseName}`
|
|
107
110
|
},
|
|
108
111
|
result: {
|
|
109
|
-
value:
|
|
112
|
+
value: result,
|
|
110
113
|
tracked: false,
|
|
111
114
|
},
|
|
112
115
|
source: 'P0',
|
|
113
116
|
stacktraceOpts: {
|
|
114
|
-
constructorOpt:
|
|
115
|
-
prependFrames: [
|
|
117
|
+
constructorOpt: hooked,
|
|
118
|
+
prependFrames: [orig]
|
|
116
119
|
},
|
|
117
120
|
tags: strInfo.tags,
|
|
118
121
|
});
|
|
@@ -139,21 +142,47 @@ module.exports = function(core) {
|
|
|
139
142
|
http.install = function() {
|
|
140
143
|
depHooks.resolve({ name: 'http' }, (http) => {
|
|
141
144
|
{
|
|
142
|
-
const name = 'http.ServerResponse.prototype.write';
|
|
143
145
|
const method = 'write';
|
|
144
146
|
patcher.patch(http.ServerResponse.prototype, method, {
|
|
145
|
-
name,
|
|
147
|
+
name: 'http.ServerResponse.prototype.write',
|
|
146
148
|
patchType,
|
|
147
|
-
pre: preHook(
|
|
149
|
+
pre: preHook('http', 'ServerResponse', method),
|
|
148
150
|
});
|
|
149
151
|
}
|
|
150
152
|
{
|
|
151
|
-
const name = 'http.ServerResponse.prototype.end';
|
|
152
153
|
const method = 'end';
|
|
153
154
|
patcher.patch(http.ServerResponse.prototype, method, {
|
|
154
|
-
name,
|
|
155
|
+
name: 'http.ServerResponse.prototype.end',
|
|
155
156
|
patchType,
|
|
156
|
-
pre: preHook(
|
|
157
|
+
pre: preHook('http', 'ServerResponse', method),
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
depHooks.resolve({ name: 'http2' }, (http2) => {
|
|
162
|
+
{
|
|
163
|
+
const method = 'write';
|
|
164
|
+
patcher.patch(http2.Http2ServerResponse.prototype, method, {
|
|
165
|
+
name: 'http2.Http2ServerResponse.prototype.write',
|
|
166
|
+
patchType,
|
|
167
|
+
pre: preHook('http2', 'Http2ServerResponse', method),
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
{
|
|
171
|
+
const method = 'end';
|
|
172
|
+
patcher.patch(http2.Http2ServerResponse.prototype, method, {
|
|
173
|
+
name: 'http2.Http2ServerResponse.prototype.end',
|
|
174
|
+
patchType,
|
|
175
|
+
pre: preHook('http2', 'Http2ServerResponse', method),
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
depHooks.resolve({ name: 'spdy', file: 'lib/spdy/response.js' }, (response) => {
|
|
180
|
+
{
|
|
181
|
+
const method = 'end';
|
|
182
|
+
patcher.patch(response, method, {
|
|
183
|
+
name: 'spdy.response.end',
|
|
184
|
+
patchType,
|
|
185
|
+
pre: preHook('spdy', 'response', method),
|
|
157
186
|
});
|
|
158
187
|
}
|
|
159
188
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contrast/assess",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.30.0",
|
|
4
4
|
"description": "Contrast service providing framework-agnostic Assess support",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"test": "../scripts/test.sh"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@contrast/common": "1.21.
|
|
20
|
+
"@contrast/common": "1.21.3",
|
|
21
21
|
"@contrast/distringuish": "^5.0.0",
|
|
22
22
|
"@contrast/scopes": "1.4.1"
|
|
23
23
|
}
|