Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 493a31d

Browse files
committed
more fixes based on review
1 parent bec522f commit 493a31d

5 files changed

Lines changed: 36 additions & 46 deletions

File tree

javascript/ql/src/Security/CWE-834/TaintedLength.qhelp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
<p>
88
Iterating the elements of an untrusted object using the
99
<code>.length</code> property can lead to a server looping
10-
indefinitely or crashing. This looping or crashing creates a
11-
denial-of-service or DOS.
12-
This happens when the server expects an array but an attacker creates
13-
a JSON object with an absurdly large number in the .length property
14-
that the server then loops through.
10+
indefinitely. This looping causes a denial-of-service or DoS by
11+
causing the server to hang or run out of memory.
12+
This happens when the server expects an array but an attacker sends
13+
a regular JSON object with an huge number in the
14+
<code>.length</code> property, such as `{length: 1e100}`, that the
15+
server then loops through.
1516
</p>
1617
</overview>
1718

@@ -35,7 +36,7 @@
3536
This is not secure since an attacker can control the value of
3637
<code>obj.length</code>, and thereby cause the loop to loop
3738
indefinitely.
38-
Here the potential DOS is fixed by enforcing that the user controlled
39+
Here the potential DoS is fixed by enforcing that the user controlled
3940
object is an array.
4041
</p>
4142

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,13 @@
1-
'use strict';
2-
31
var express = require('express');
4-
var router = new express.Router();
5-
var rootRoute = router.route('foobar');
2+
var app = express();
63

7-
rootRoute.post(function(req, res) {
4+
app.post("/foo", (req, res) => {
85
var obj = req.body;
96

10-
calcStuff(obj);
11-
});
12-
13-
function calcStuff(obj) {
147
var ret = [];
158

16-
// potential DOS if obj.length is large.
9+
// potential DoS if obj.length is large.
1710
for (var i = 0; i < obj.length; i++) {
1811
ret.push(obj[i]);
1912
}
20-
21-
return ret;
22-
}
13+
});
Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,16 @@
1-
'use strict';
2-
31
var express = require('express');
4-
var router = new express.Router();
5-
var rootRoute = router.route('foobar');
2+
var app = express();
63

7-
rootRoute.post(function(req, res) {
4+
app.post("/foo", (req, res) => {
85
var obj = req.body;
9-
10-
calcStuff(obj);
11-
});
12-
13-
function calcStuff(obj) {
6+
147
if (!(obj instanceof Array)) { // prevents DOS
158
return [];
169
}
1710

1811
var ret = [];
12+
1913
for (var i = 0; i < obj.length; i++) {
2014
ret.push(obj[i]);
2115
}
22-
23-
return ret;
24-
}
16+
});

javascript/ql/src/semmle/javascript/security/dataflow/TaintedLength.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ module TaintedLength {
1717
* A taint-tracking configuration for reasoning about looping on tainted objects with unbounded length.
1818
*/
1919
class Configuration extends TaintTracking::Configuration {
20-
Configuration() { this = "LabeledLoopTaintedObject" }
20+
Configuration() { this = "TaintedLength" }
2121

2222
override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) {
2323
source instanceof Source and label = TaintedObject::label()

javascript/ql/src/semmle/javascript/security/dataflow/TaintedLengthCustomizations.qll

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,14 @@ module TaintedLength {
3636
class ArrayIterationLoop extends Stmt {
3737
LocalVariable indexVariable;
3838
LoopStmt loop;
39+
DataFlow::PropRead lengthRead;
3940

4041
ArrayIterationLoop() {
4142
this = loop and
42-
exists(RelationalComparison compare, DataFlow::PropRead lengthRead |
43+
exists(RelationalComparison compare |
4344
compare = loop.getTest() and
4445
compare.getLesserOperand() = indexVariable.getAnAccess() and
45-
lengthRead.accesses(_, "length") and
46+
lengthRead.getPropertyName() = "length" and
4647
lengthRead.flowsToExpr(compare.getGreaterOperand())
4748
) and
4849
(
@@ -51,6 +52,13 @@ module TaintedLength {
5152
)
5253
}
5354

55+
/**
56+
* Gets the length read in the loop test
57+
*/
58+
DataFlow::PropRead getLengthRead() {
59+
result = lengthRead
60+
}
61+
5462
/**
5563
* Gets the loop test of this loop.
5664
*/
@@ -77,19 +85,17 @@ module TaintedLength {
7785
abstract class Sink extends DataFlow::Node { }
7886

7987
/**
80-
* A loop that iterates over an array, such as `for (..; .. sink.length; ...) ...`
88+
* An object that that is being iterated in a `for` loop, such as `for (..; .. sink.length; ...) ...`
8189
*/
8290
private class LoopSink extends Sink {
8391
LoopSink() {
84-
exists(ArrayIterationLoop loop, Expr lengthAccess, DataFlow::PropRead lengthRead |
85-
loop.getTest().(RelationalComparison).getGreaterOperand() = lengthAccess and
86-
lengthRead.flowsToExpr(lengthAccess) and
87-
lengthRead.accesses(this, "length") and
92+
exists(ArrayIterationLoop loop |
93+
this = loop.getLengthRead().getBase() and
8894

89-
// In the DOS we are looking for arrayRead will evaluate to undefined.
90-
// If an obvious nullpointer happens on this undefined, then the DOS cannot happen.
95+
// In the DOS we are looking for arrayRead will evaluate to undefined,
96+
// this may cause an exception to be thrown, thus bailing out of the loop.
97+
// A DoS cannot happen if such an exception is thrown.
9198
not exists(DataFlow::PropRead arrayRead, Expr throws |
92-
// It doesn't only happen inside the for-loop, outside is also a sink (assuming it happens before).
9399
loop.getBody().getAChild*() = arrayRead.asExpr() and
94100
loop.getBody().getAChild*() = throws and
95101
arrayRead.getPropertyNameExpr() = loop.getIndexVariable().getAnAccess() and
@@ -178,7 +184,7 @@ module TaintedLength {
178184

179185
/**
180186
* A method call to a lodash method that iterates over an array-like structure,
181-
* such as `_.filter(sink, ...)`
187+
* such as `_.filter(sink, ...)`.
182188
*/
183189
private class LodashIterationSink extends Sink {
184190
DataFlow::CallNode call;
@@ -202,7 +208,7 @@ module TaintedLength {
202208
isCrashingWithNullValues(throws)
203209
)
204210
or
205-
// similar to the loop sink - the existance of an early-exit usually means that no DOS can happen.
211+
// similar to the loop sink - the existence of an early-exit usually means that no DOS can happen.
206212
exists(ThrowStmt throw |
207213
throw = func.asExpr().(Function).getBody().getAChild*() and
208214
throw.getTarget() = func.asExpr()
@@ -214,7 +220,7 @@ module TaintedLength {
214220
}
215221

216222
/**
217-
* A source of objects that can cause DOS is looped over.
223+
* A source of objects that can cause DOS if looped over.
218224
*/
219225
abstract class Source extends DataFlow::Node { }
220226

0 commit comments

Comments
 (0)