Skip to content

Commit 7e6f2d1

Browse files
authored
Merge pull request #14681 from atorralba/atorralba/java/weak-randomness-cve-coverage
Java: Add more sinks to the Insecure Randomness query
2 parents 6636c76 + 66b54f0 commit 7e6f2d1

File tree

12 files changed

+179
-20
lines changed

12 files changed

+179
-20
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
extensions:
2+
- addsTo:
3+
pack: codeql/java-all
4+
extensible: sinkModel
5+
data:
6+
- ["org.pac4j.jwt.config.encryption", "SecretEncryptionConfiguration", True, "SecretEncryptionConfiguration", "", "", "Argument[0]", "credentials-key", "manual"]
7+
- ["org.pac4j.jwt.config.encryption", "SecretEncryptionConfiguration", True, "setSecret", "", "", "Argument[0]", "credentials-key", "manual"]
8+
- ["org.pac4j.jwt.config.encryption", "SecretEncryptionConfiguration", True, "setSecretBase64", "", "", "Argument[0]", "credentials-key", "manual"]
9+
- ["org.pac4j.jwt.config.encryption", "SecretEncryptionConfiguration", True, "setSecretBytes", "", "", "Argument[0]", "credentials-key", "manual"]
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
extensions:
2+
- addsTo:
3+
pack: codeql/java-all
4+
extensible: sinkModel
5+
data:
6+
- ["org.pac4j.jwt.config.signature", "SecretSignatureConfiguration", True, "SecretEncryptionConfiguration", "", "", "Argument[0]", "credentials-key", "manual"]
7+
- ["org.pac4j.jwt.config.signature", "SecretSignatureConfiguration", True, "setSecret", "", "", "Argument[0]", "credentials-key", "manual"]
8+
- ["org.pac4j.jwt.config.signature", "SecretSignatureConfiguration", True, "setSecretBase64", "", "", "Argument[0]", "credentials-key", "manual"]
9+
- ["org.pac4j.jwt.config.signature", "SecretSignatureConfiguration", True, "setSecretBytes", "", "", "Argument[0]", "credentials-key", "manual"]
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/** Provides definitions related to the Netty framework. */
2+
3+
import java
4+
5+
/** The interface `Cookie` in the packages `io.netty.handler.codec.http` and `io.netty.handler.codec.http.cookie`. */
6+
class NettyCookie extends Interface {
7+
NettyCookie() { this.hasQualifiedName("io.netty.handler.codec.http" + [".cookie", ""], "Cookie") }
8+
}
9+
10+
/** The class `DefaultCookie` in the packages `io.netty.handler.codec.http` and `io.netty.handler.codec.http.cookie`. */
11+
class NettyDefaultCookie extends Class {
12+
NettyDefaultCookie() {
13+
this.hasQualifiedName("io.netty.handler.codec.http" + [".cookie", ""], "DefaultCookie")
14+
}
15+
}
16+
17+
/** The method `setValue` of the interface `Cookie` or a class implementing it. */
18+
class NettySetCookieValueMethod extends Method {
19+
NettySetCookieValueMethod() {
20+
this.getDeclaringType*() instanceof NettyCookie and
21+
this.hasName("setValue")
22+
}
23+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/**
2+
* Provides classes and predicates for working with the OpenSAML libraries.
3+
*/
4+
5+
import java
6+
private import semmle.code.java.security.InsecureRandomnessQuery
7+
8+
/** The interface `org.opensaml.saml.saml2.core.RequestAbstractType`. */
9+
class SamlRequestAbstractType extends Interface {
10+
SamlRequestAbstractType() {
11+
this.hasQualifiedName("org.opensaml.saml.saml2.core", "RequestAbstractType")
12+
}
13+
}
14+
15+
/** The method `setID` of the interface `RequestAbstractType`. */
16+
class SamlRequestSetIdMethod extends Method {
17+
SamlRequestSetIdMethod() {
18+
this.getDeclaringType() instanceof SamlRequestAbstractType and
19+
this.hasName("setID")
20+
}
21+
}
22+
23+
private class SamlRequestSetIdSink extends InsecureRandomnessSink {
24+
SamlRequestSetIdSink() {
25+
exists(MethodCall c | c.getMethod() instanceof SamlRequestSetIdMethod |
26+
c.getArgument(0) = this.asExpr()
27+
)
28+
}
29+
}

java/ql/lib/semmle/code/java/frameworks/Servlets.qll

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ class TypeCookie extends Class {
244244
}
245245

246246
/**
247-
* The method `getValue(String)` declared in `javax.servlet.http.Cookie`.
247+
* The method `getValue()` declared in `javax.servlet.http.Cookie`.
248248
*/
249249
class CookieGetValueMethod extends Method {
250250
CookieGetValueMethod() {
@@ -254,6 +254,16 @@ class CookieGetValueMethod extends Method {
254254
}
255255
}
256256

257+
/**
258+
* The method `setValue(String)` declared in `javax.servlet.http.Cookie`.
259+
*/
260+
class CookieSetValueMethod extends Method {
261+
CookieSetValueMethod() {
262+
this.getDeclaringType() instanceof TypeCookie and
263+
this.hasName("setValue")
264+
}
265+
}
266+
257267
/**
258268
* The method `getName()` declared in `javax.servlet.http.Cookie`.
259269
*/
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/** Provides definitions to reason about HTTP cookies. */
2+
3+
import java
4+
private import semmle.code.java.frameworks.Netty
5+
private import semmle.code.java.frameworks.Servlets
6+
7+
/** An expression setting the value of a cookie. */
8+
abstract class SetCookieValue extends Expr { }
9+
10+
private class ServletSetCookieValue extends SetCookieValue {
11+
ServletSetCookieValue() {
12+
exists(Call c |
13+
c.(ClassInstanceExpr).getConstructedType() instanceof TypeCookie and
14+
this = c.getArgument(1)
15+
or
16+
c.(MethodCall).getMethod() instanceof CookieSetValueMethod and
17+
this = c.getArgument(0)
18+
)
19+
}
20+
}
21+
22+
private class NettySetCookieValue extends SetCookieValue {
23+
NettySetCookieValue() {
24+
exists(Call c |
25+
c.(ClassInstanceExpr).getConstructedType() instanceof NettyDefaultCookie and
26+
this = c.getArgument(1)
27+
or
28+
c.(MethodCall).getMethod() instanceof NettySetCookieValueMethod and
29+
this = c.getArgument(0)
30+
)
31+
}
32+
}

java/ql/lib/semmle/code/java/security/InsecureRandomnessQuery.qll

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
/** Provides classes and predicates for reasoning about insecure randomness. */
22

33
import java
4+
private import semmle.code.java.frameworks.OpenSaml
45
private import semmle.code.java.frameworks.Servlets
5-
private import semmle.code.java.security.SensitiveActions
6-
private import semmle.code.java.security.SensitiveApi
7-
private import semmle.code.java.dataflow.TaintTracking
86
private import semmle.code.java.dataflow.ExternalFlow
7+
private import semmle.code.java.dataflow.TaintTracking
8+
private import semmle.code.java.security.Cookies
99
private import semmle.code.java.security.RandomQuery
10+
private import semmle.code.java.security.SensitiveActions
11+
private import semmle.code.java.security.SensitiveApi
1012

1113
/**
1214
* A node representing a source of insecure randomness.
@@ -18,7 +20,7 @@ abstract class InsecureRandomnessSource extends DataFlow::Node { }
1820
private class RandomMethodSource extends InsecureRandomnessSource {
1921
RandomMethodSource() {
2022
exists(RandomDataSource s | this.asExpr() = s.getOutput() |
21-
not s.getQualifier().getType() instanceof SafeRandomImplementation
23+
not s.getSourceOfRandomness() instanceof SafeRandomImplementation
2224
)
2325
}
2426
}
@@ -40,24 +42,15 @@ private class TypeHadoopOsSecureRandom extends SafeRandomImplementation {
4042
}
4143

4244
/**
43-
* A node representing an operation which should not use a Insecurely random value.
45+
* A node representing an operation which should not use an insecurely random value.
4446
*/
4547
abstract class InsecureRandomnessSink extends DataFlow::Node { }
4648

4749
/**
4850
* A node which sets the value of a cookie.
4951
*/
5052
private class CookieSink extends InsecureRandomnessSink {
51-
CookieSink() {
52-
exists(Call c |
53-
c.(ClassInstanceExpr).getConstructedType() instanceof TypeCookie and
54-
this.asExpr() = c.getArgument(1)
55-
or
56-
c.(MethodCall).getMethod().getDeclaringType() instanceof TypeCookie and
57-
c.(MethodCall).getMethod().hasName("setValue") and
58-
this.asExpr() = c.getArgument(0)
59-
)
60-
}
53+
CookieSink() { this.asExpr() instanceof SetCookieValue }
6154
}
6255

6356
private class SensitiveActionSink extends InsecureRandomnessSink {
@@ -76,6 +69,8 @@ module InsecureRandomnessConfig implements DataFlow::ConfigSig {
7669

7770
predicate isBarrierIn(DataFlow::Node n) { isSource(n) }
7871

72+
predicate isBarrierOut(DataFlow::Node n) { isSink(n) }
73+
7974
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
8075
n1.asExpr() = n2.asExpr().(BinaryExpr).getAnOperand()
8176
or
@@ -88,6 +83,17 @@ module InsecureRandomnessConfig implements DataFlow::ConfigSig {
8883
n1.asExpr() = mc.getArgument(0) and
8984
n2.asExpr() = mc
9085
)
86+
or
87+
// TODO: Once we have a default sanitizer for UUIDs, we can convert these to global summaries.
88+
exists(Call c |
89+
c.(ClassInstanceExpr).getConstructedType().hasQualifiedName("java.util", "UUID") and
90+
n1.asExpr() = c.getAnArgument() and
91+
n2.asExpr() = c
92+
or
93+
c.(MethodCall).getMethod().hasQualifiedName("java.util", "UUID", "toString") and
94+
n1.asExpr() = c.getQualifier() and
95+
n2.asExpr() = c
96+
)
9197
}
9298
}
9399

java/ql/lib/semmle/code/java/security/RandomDataSource.qll

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*/
44

55
import java
6+
private import semmle.code.java.dataflow.TypeFlow
67

78
/**
89
* A method access that returns random data or writes random data to an argument.
@@ -43,6 +44,9 @@ abstract class RandomDataSource extends MethodCall {
4344
* in the case where it writes random data to that argument.
4445
*/
4546
abstract Expr getOutput();
47+
48+
/** Gets the type of the source of randomness used by this call. */
49+
RefType getSourceOfRandomness() { boundOrStaticType(this.getQualifier(), result) }
4650
}
4751

4852
/**
@@ -167,4 +171,18 @@ class ApacheCommonsRandomStringSource extends RandomDataSource {
167171
}
168172

169173
override Expr getOutput() { result = this }
174+
175+
override RefType getSourceOfRandomness() {
176+
if
177+
this.getMethod().hasStringSignature("random(int, int, int, boolean, boolean, char[], Random)")
178+
then boundOrStaticType(this.getArgument(6), result)
179+
else result.hasQualifiedName("java.util", "Random")
180+
}
181+
}
182+
183+
/** Holds if `t` is the static type of `e`, or an upper bound of the runtime type of `e`. */
184+
private predicate boundOrStaticType(Expr e, RefType t) {
185+
exprTypeFlow(e, t, false)
186+
or
187+
t = e.getType()
170188
}

java/ql/test/query-tests/security/CWE-330/WeakRandomCookies.java renamed to java/ql/test/query-tests/security/CWE-330/InsecureRandomCookies.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import org.apache.commons.lang3.RandomStringUtils;
1111
import org.owasp.esapi.Encoder;
1212

13-
public class WeakRandomCookies extends HttpServlet {
13+
public class InsecureRandomCookies extends HttpServlet {
1414
HttpServletResponse response;
1515

1616
public void doGet() {
@@ -19,6 +19,14 @@ public void doGet() {
1919
int c = r.nextInt();
2020
// BAD: The cookie value may be predictable.
2121
Cookie cookie = new Cookie("name", Integer.toString(c)); // $hasWeakRandomFlow
22+
cookie.setValue(Integer.toString(c)); // $hasWeakRandomFlow
23+
24+
io.netty.handler.codec.http.Cookie nettyCookie =
25+
new io.netty.handler.codec.http.DefaultCookie("name", Integer.toString(c)); // $hasWeakRandomFlow
26+
nettyCookie.setValue(Integer.toString(c)); // $hasWeakRandomFlow
27+
io.netty.handler.codec.http.cookie.Cookie nettyCookie2 =
28+
new io.netty.handler.codec.http.cookie.DefaultCookie("name", Integer.toString(c)); // $hasWeakRandomFlow
29+
nettyCookie2.setValue(Integer.toString(c)); // $hasWeakRandomFlow
2230

2331
Encoder enc = null;
2432
int c2 = r.nextInt();
@@ -36,8 +44,8 @@ public void doGet() {
3644
byte[] bytes2 = new byte[16];
3745
sr.nextBytes(bytes2);
3846
// GOOD: The cookie value is unpredictable.
39-
Cookie cookie4 = new Cookie("name", new String(bytes2));
40-
47+
Cookie cookie4 = new Cookie("name", new String(bytes2));
48+
4149
ThreadLocalRandom tlr = ThreadLocalRandom.current();
4250

4351
Cookie cookie5 = new Cookie("name", Integer.toString(tlr.nextInt())); // $hasWeakRandomFlow
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/apache-commons-lang3-3.7:${testdir}/../../../stubs/esapi-2.0.1
1+
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/apache-commons-lang3-3.7:${testdir}/../../../stubs/esapi-2.0.1:${testdir}/../../../stubs/netty-4.1.x

0 commit comments

Comments
 (0)