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

Skip to content

Commit 9f986ca

Browse files
committed
Add Weak Randomness Query
1 parent 8d724ac commit 9f986ca

4 files changed

Lines changed: 196 additions & 0 deletions

File tree

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
<p>
7+
Using a cryptographically weak pseudo-random number generator to generate a security-sensitive value,
8+
such as a password, makes it easier for an attacker to predict the value.
9+
</p>
10+
<p>
11+
Pseudo-random number generators generate a sequence of numbers that only approximates the properties
12+
of random numbers. The sequence is not truly random because it is completely determined by a
13+
relatively small set of initial values, the seed. If the random number generator is
14+
cryptographically weak, then this sequence may be easily predictable through outside observations.
15+
</p>
16+
17+
</overview>
18+
<recommendation>
19+
<p>
20+
Use a cryptographically secure pseudo-random number generator if the output is to be used in a
21+
security-sensitive context. As a rule of thumb, a value should be considered "security-sensitive"
22+
if predicting it would allow the attacker to perform an action that they would otherwise be unable
23+
to perform. For example, if an attacker could predict the random password generated for a new user,
24+
they would be able to log in as that new user.
25+
</p>
26+
27+
<p>
28+
For Java, <code>java.util.Random</code> is not cryptographically secure. Use <code>java.security.SecureRandom</code> instead.
29+
</p>
30+
</recommendation>
31+
32+
<example>
33+
34+
<p>
35+
The following examples show different ways of generating a cookie with a random value.
36+
</p>
37+
38+
<p>
39+
In the first case, we generate a fresh cookie by appending a random integer to the end of a static
40+
string. The random number generator used (<code>Random</code>) is not cryptographically secure,
41+
so it may be possible for an attacker to predict the generated cookie.
42+
</p>
43+
44+
<sample src="examples/InsecureRandomnessCookie.java" />
45+
46+
<p>
47+
In the second case, we generate a fresh cookie by appending a random integer to the end of a static
48+
string. The random number generator used (<code>SecureRandom</code>) is cryptographically secure,
49+
so it is not possible for an attacker to predict the generated cookie.
50+
</p>
51+
52+
<sample src="examples/SecureRandomnessCookie.java" />
53+
54+
</example>
55+
56+
<references>
57+
<li>Wikipedia: <a href="http://en.wikipedia.org/wiki/Pseudorandom_number_generator">Pseudo-random number generator</a>.</li>
58+
<li>
59+
Java Docs: <a href="http://docs.oracle.com/javase/8/docs/api/java/util/Random.html">Random</a>.
60+
</li>
61+
<li>
62+
Java Docs: <a href="http://docs.oracle.com/javase/8/docs/api/java/security/SecureRandom.html">SecureRandom</a>.
63+
</li>
64+
</references>
65+
</qhelp>
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/**
2+
* @name Weak Randomness
3+
* @description Using a weak source of randomness may allow an attacker to predict the generated values.
4+
* @kind path-problem
5+
* @problem.severity error
6+
* @security-severity 8.6
7+
* @precision high
8+
* @id java/weak-randomness
9+
* @tags security
10+
* external/cwe/cwe-330
11+
* external/cwe/cwe-338
12+
*/
13+
14+
import java
15+
import semmle.code.java.frameworks.Servlets
16+
import semmle.code.java.dataflow.TaintTracking
17+
import semmle.code.java.security.RandomQuery
18+
import WeakRandomnessFlow::PathGraph
19+
20+
/**
21+
* The `java.util.Random` class.
22+
*/
23+
class TypeRandom extends RefType {
24+
TypeRandom() { this.hasQualifiedName("java.util", "Random") }
25+
}
26+
27+
abstract class WeakRandomnessSource extends DataFlow::Node { }
28+
29+
private class JavaRandomSource extends WeakRandomnessSource {
30+
JavaRandomSource() {
31+
this.asExpr().getType() instanceof TypeRandom and this.asExpr() instanceof ConstructorCall
32+
}
33+
}
34+
35+
private class MathRandomMethodAccess extends WeakRandomnessSource {
36+
MathRandomMethodAccess() {
37+
exists(MethodAccess ma | this.asExpr() = ma |
38+
ma.getMethod().hasName("random") and
39+
ma.getMethod().getDeclaringType().hasQualifiedName("java.lang", "Math")
40+
)
41+
}
42+
}
43+
44+
abstract private class SafeRandomImplementation extends RefType { }
45+
46+
private class TypeSecureRandom extends SafeRandomImplementation {
47+
TypeSecureRandom() { this.hasQualifiedName("java.security", "SecureRandom") }
48+
}
49+
50+
private class TypeHadoopOsSecureRandom extends SafeRandomImplementation {
51+
TypeHadoopOsSecureRandom() {
52+
this.hasQualifiedName("org.apache.hadoop.crypto.random", "OsSecureRandom")
53+
}
54+
}
55+
56+
abstract class WeakRandomnessAdditionalTaintStep extends Unit {
57+
abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);
58+
}
59+
60+
abstract class WeakRandomnessSink extends DataFlow::Node { }
61+
62+
private class CookieSink extends WeakRandomnessSink {
63+
CookieSink() {
64+
this.asExpr().getType() instanceof TypeCookie and
65+
exists(MethodAccess ma | ma.getMethod().hasName("addCookie") |
66+
ma.getArgument(0) = this.asExpr()
67+
)
68+
}
69+
}
70+
71+
/**
72+
* Holds if there is a method access which converts `bytes` to the string `str`.
73+
*/
74+
private predicate covertsBytesToString(DataFlow::Node bytes, DataFlow::Node str) {
75+
bytes.getType().(Array).getElementType().(PrimitiveType).hasName("byte") and
76+
str.getType() instanceof TypeString and
77+
exists(MethodAccess ma | ma = str.asExpr() | bytes.asExpr() = ma.getAnArgument())
78+
}
79+
80+
/**
81+
* A taint-tracking configuration for weak randomness.
82+
*/
83+
module WeakRandomnessConfig implements DataFlow::ConfigSig {
84+
predicate isSource(DataFlow::Node src) { src instanceof WeakRandomnessSource }
85+
86+
predicate isSink(DataFlow::Node sink) { sink instanceof WeakRandomnessSink }
87+
88+
predicate isBarrier(DataFlow::Node n) { n.getTypeBound() instanceof SafeRandomImplementation }
89+
90+
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
91+
exists(MethodAccess ma, Method m |
92+
n1.asExpr() = ma.getQualifier() and
93+
ma.getMethod() = m and
94+
m.getDeclaringType() instanceof TypeRandom and
95+
(
96+
m.hasName(["nextInt", "nextLong", "nextFloat", "nextDouble", "nextBoolean", "nextGaussian"]) and
97+
n2.asExpr() = ma
98+
or
99+
m.hasName("nextBytes") and
100+
n2.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = ma.getArgument(0)
101+
)
102+
)
103+
or
104+
covertsBytesToString(n1, n2)
105+
}
106+
}
107+
108+
module WeakRandomnessFlow = TaintTracking::Global<WeakRandomnessConfig>;
109+
110+
from WeakRandomnessFlow::PathNode source, WeakRandomnessFlow::PathNode sink
111+
where WeakRandomnessFlow::flowPath(source, sink)
112+
select sink.getNode(), source, sink, "Potential weak randomness due to a $@.", source.getNode(),
113+
"weak randomness source."
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Random r = new Random();
2+
3+
byte[] bytes = new byte[16];
4+
r.nextBytes(bytes);
5+
6+
String cookieValue = encode(bytes);
7+
8+
Cookie cookie = new Cookie("name", cookieValue);
9+
response.addCookie(cookie);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
SecureRandom r = new SecureRandom();
2+
3+
byte[] bytes = new byte[16];
4+
r.nextBytes(bytes);
5+
6+
String cookieValue = encode(bytes);
7+
8+
Cookie cookie = new Cookie("name", cookieValue);
9+
response.addCookie(cookie);

0 commit comments

Comments
 (0)