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

Skip to content

Commit 7e8fd80

Browse files
committed
use steps from InsecureRandomness, and use small-steps
1 parent 9029dba commit 7e8fd80

3 files changed

Lines changed: 32 additions & 20 deletions

File tree

javascript/ql/src/Security/CWE-327/BadRandomness.ql

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import javascript
1414
private import semmle.javascript.dataflow.InferredTypes
1515
private import semmle.javascript.dataflow.internal.StepSummary
16+
private import semmle.javascript.security.dataflow.InsecureRandomnessCustomizations
1617

1718
/**
1819
* Gets a Buffer/TypedArray containing cryptographically secure random numbers.
@@ -29,7 +30,9 @@ private DataFlow::SourceNode randomBufferSource() {
2930
or
3031
result = DataFlow::moduleImport("secure-random").getACall()
3132
or
32-
result = DataFlow::moduleImport("secure-random").getAMethodCall(["randomArray", "randomUint8Array", "randomBuffer"])
33+
result =
34+
DataFlow::moduleImport("secure-random")
35+
.getAMethodCall(["randomArray", "randomUint8Array", "randomBuffer"])
3336
}
3437

3538
/**
@@ -41,48 +44,50 @@ private string prop() { result = DataFlow::PseudoProperties::setElement() }
4144
/**
4245
* Gets a reference to a cryptographically secure random number, type tracked using `t`.
4346
*/
44-
private DataFlow::SourceNode goodRandom(DataFlow::TypeTracker t) {
47+
private DataFlow::Node goodRandom(DataFlow::TypeTracker t) {
4548
t.startInProp(prop()) and
4649
result = randomBufferSource()
4750
or
4851
// Loading a number from a `Buffer`.
4952
exists(DataFlow::TypeTracker t2 | t = t2.append(LoadStep(prop())) |
5053
// the random generators return arrays/Buffers of random numbers, we therefore track through an indexed read.
51-
exists(DataFlow::PropRead read |
54+
exists(DataFlow::PropRead read | result = read |
5255
read.getBase() = goodRandom(t2) and
53-
exists(read.getPropertyNameExpr())
56+
not read.getPropertyNameExpr() instanceof Label
5457
)
5558
or
5659
// reading a number from a Buffer.
57-
exists(DataFlow::MethodCallNode call |
58-
call.getReceiver().getALocalSource() = goodRandom(t.continue()) and
60+
exists(DataFlow::MethodCallNode call | result = call |
61+
call.getReceiver() = goodRandom(t2) and
5962
call
6063
.getMethodName()
6164
.regexpMatch("read(BigInt|BigUInt|Double|Float|Int|UInt)(8|16|32|64)?(BE|LE)?")
6265
)
6366
)
6467
or
65-
exists(DataFlow::TypeTracker t2 | result = goodRandom(t2).track(t2, t))
68+
exists(DataFlow::TypeTracker t2 | t = t2.smallstep(goodRandom(t2), result))
6669
or
67-
// re-using the collection steps for `Set`.
70+
// re-using the collection steps for `Set`.
6871
exists(DataFlow::TypeTracker t2 |
6972
result = CollectionsTypeTracking::collectionStep(goodRandom(t2), t, t2)
7073
)
74+
or
75+
InsecureRandomness::isAdditionalTaintStep(goodRandom(t.continue()), result)
7176
}
7277

7378
/**
7479
* Gets a reference to a cryptographically random number.
7580
*/
76-
DataFlow::SourceNode goodRandom() { result = goodRandom(DataFlow::TypeTracker::end()) }
81+
DataFlow::Node goodRandom() { result = goodRandom(DataFlow::TypeTracker::end()) }
7782

7883
/**
7984
* Gets a node that that produces a biased result from otherwise cryptographically secure random numbers.
8085
*/
8186
DataFlow::Node badCrypto(string description) {
8287
// addition and multiplication - always bad when both the lhs and rhs are random.
8388
exists(BinaryExpr binop | result.asExpr() = binop |
84-
goodRandom().flowsToExpr(binop.getLeftOperand()) and
85-
goodRandom().flowsToExpr(binop.getRightOperand()) and
89+
goodRandom().asExpr() = binop.getLeftOperand() and
90+
goodRandom().asExpr() = binop.getRightOperand() and
8691
(
8792
binop.getOperator() = "+" and description = "addition"
8893
or
@@ -92,22 +97,21 @@ DataFlow::Node badCrypto(string description) {
9297
or
9398
// division - always bad
9499
exists(DivExpr div | result.asExpr() = div |
95-
goodRandom().flowsToExpr(div.getLeftOperand()) and
100+
goodRandom().asExpr() = div.getLeftOperand() and
96101
description = "division"
97102
)
98103
or
99104
// modulo - only bad if not by a power of 2 - and the result is not checked for bias
100-
exists(ModExpr mod, DataFlow::SourceNode random |
101-
result.asExpr() = mod and mod.getOperator() = "%"
102-
|
105+
exists(ModExpr mod, DataFlow::Node random | result.asExpr() = mod and mod.getOperator() = "%" |
103106
description = "modulo" and
104107
goodRandom() = random and
105-
random.flowsToExpr(mod.getLeftOperand()) and
106-
// division by a power of 2 is OK. E.g. if `x` is uniformly random is in the range [0..255] then `x % 32` is uniformly random in the range [0..31].
108+
random.asExpr() = mod.getLeftOperand() and
109+
// division by a power of 2 is OK. E.g. if `x` is uniformly random is in the range [0..255] then `x % 32` is uniformly random in the range [0..31].
107110
not mod.getRightOperand().getIntValue() = [2, 4, 8, 16, 32, 64, 128] and
108111
// not exists a comparison that checks if the result is potentially biased.
109112
not exists(BinaryExpr comparison | comparison.getOperator() = [">", "<", "<=", ">="] |
110-
AccessPath::getAnAliasedSourceNode(random).flowsToExpr(comparison.getAnOperand())
113+
AccessPath::getAnAliasedSourceNode(random.getALocalSource())
114+
.flowsToExpr(comparison.getAnOperand())
111115
or
112116
exists(DataFlow::PropRead otherRead |
113117
otherRead = random.(DataFlow::PropRead).getBase().getALocalSource().getAPropertyRead() and
@@ -121,7 +125,7 @@ DataFlow::Node badCrypto(string description) {
121125
exists(DataFlow::CallNode number, StringOps::ConcatenationRoot root | result = number |
122126
number = DataFlow::globalVarRef(["Number", "parseInt", "parseFloat"]).getACall() and
123127
root = number.getArgument(0) and
124-
goodRandom().flowsTo(root.getALeaf()) and
128+
goodRandom() = root.getALeaf() and
125129
exists(root.getALeaf().getStringValue()) and
126130
description = "string concatenation"
127131
)

javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@
66
| bad-random.js:73:32:73:42 | byte / 25.6 | Using division on cryptographically random numbers produces biased results. |
77
| bad-random.js:75:21:75:30 | byte % 100 | Using modulo on cryptographically random numbers produces biased results. |
88
| bad-random.js:81:11:81:51 | secureR ... (10)[0] | Using addition on cryptographically random numbers produces biased results. |
9+
| bad-random.js:85:11:85:35 | goodRan ... Random2 | Using addition on cryptographically random numbers produces biased results. |
10+
| bad-random.js:87:16:87:24 | bad + bad | Using addition on cryptographically random numbers produces biased results. |

javascript/ql/test/query-tests/Security/CWE-327/bad-random.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,10 @@ function setSteps() {
7878

7979
const secureRandom = require("secure-random");
8080

81-
var bad = secureRandom(10)[0] + secureRandom(10)[0]; // NOT OK
81+
var bad = secureRandom(10)[0] + secureRandom(10)[0]; // NOT OK
82+
83+
var goodRandom1 = 5 + secureRandom(10)[0];
84+
var goodRandom2 = 5 + secureRandom(10)[0];
85+
var bad = goodRandom1 + goodRandom2; // NOT OK
86+
87+
var dontFlag = bad + bad; // OK - the operands have already been flagged - but flagged anyway due to us not detecting that [INCONSISTENCY].

0 commit comments

Comments
 (0)