Skip to content

Commit 2e08c5d

Browse files
committed
Refactored HttpsUrls.ql
1 parent c3c7337 commit 2e08c5d

File tree

4 files changed

+132
-49
lines changed

4 files changed

+132
-49
lines changed

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

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,20 @@ class UriCreation extends Call {
5252
/**
5353
* Gets the host argument of the newly created URI. In the case where the
5454
* host is specified separately, this is only the host. In the case where the
55-
* uri is parsed from an input string, such as in
55+
* URI is parsed from an input string, such as in
5656
* `URI("http://foo.com/mypath")`, this is the entire argument passed in,
5757
* that is `"http://foo.com/mypath"`.
5858
*/
59-
Expr getHostArg() { none() }
59+
abstract Expr getHostArg();
60+
61+
/**
62+
* Gets the scheme argument of the newly created URI. In the case where the
63+
* scheme is specified separately, this is only the scheme. In the case where the
64+
* URI is parsed from an input string, such as in
65+
* `URI("http://foo.com/mypath")`, this is the entire argument passed in,
66+
* that is `"http://foo.com/mypath"`.
67+
*/
68+
abstract Expr getSchemeArg();
6069
}
6170

6271
/** A `java.net.URI` constructor call. */
@@ -74,13 +83,17 @@ class UriConstructorCall extends ClassInstanceExpr, UriCreation {
7483
// String fragment)
7584
result = this.getArgument(2) and this.getNumArgument() = 7
7685
}
86+
87+
override Expr getSchemeArg() { result = this.getArgument(0) }
7788
}
7889

7990
/** A call to `java.net.URI::create`. */
8091
class UriCreate extends UriCreation {
8192
UriCreate() { this.getCallee().hasName("create") }
8293

8394
override Expr getHostArg() { result = this.getArgument(0) }
95+
96+
override Expr getSchemeArg() { result = this.getArgument(0) }
8497
}
8598

8699
/** A `java.net.URL` constructor call. */
@@ -105,7 +118,7 @@ class UrlConstructorCall extends ClassInstanceExpr {
105118
}
106119

107120
/** Gets the argument that corresponds to the protocol of the URL. */
108-
Expr protocolArg() {
121+
Expr getProtocolArg() {
109122
// In all cases except where the first parameter is a URL, the argument
110123
// containing the protocol is the first one, otherwise it is the second.
111124
if this.getConstructor().getParameterType(0) instanceof TypeUrl
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import java
2+
private import semmle.code.java.dataflow.DataFlow
3+
private import semmle.code.java.dataflow.ExternalFlow
4+
private import semmle.code.java.dataflow.TaintTracking
5+
private import semmle.code.java.frameworks.ApacheHttp
6+
private import semmle.code.java.frameworks.Networking
7+
8+
/**
9+
* String of HTTP URLs not in private domains.
10+
*/
11+
class HttpStringLiteral extends StringLiteral {
12+
HttpStringLiteral() {
13+
exists(string s | this.getRepresentedString() = s |
14+
s = "http"
15+
or
16+
s.matches("http://%") and
17+
not s.substring(7, s.length()) instanceof PrivateHostName and
18+
not TaintTracking::localExprTaint(any(StringLiteral p |
19+
p.getRepresentedString() instanceof PrivateHostName
20+
), this.getParent*())
21+
)
22+
}
23+
}
24+
25+
/**
26+
* A sink that represents a URL opening method call, such as a call to `java.net.URL.openConnection()`.
27+
*/
28+
abstract class UrlOpenSink extends DataFlow::Node { }
29+
30+
private class DefaultUrlOpenSink extends UrlOpenSink {
31+
DefaultUrlOpenSink() { sinkNode(this, "open-url") }
32+
}
33+
34+
/**
35+
* A unit class for adding additional taint steps.
36+
*
37+
* Extend this class to add additional taint steps that should apply
38+
* to configurations working with HTTP URLs.
39+
*/
40+
class HttpUrlsAdditionalTaintStep extends Unit {
41+
/**
42+
* Holds if the step from `node1` to `node2` should be considered a taint
43+
* step for taint tracking configurations working with HTTP URLs.
44+
*/
45+
abstract predicate step(DataFlow::Node n1, DataFlow::Node n2);
46+
}
47+
48+
private class DefaultHttpUrlAdditionalTaintStep extends HttpUrlsAdditionalTaintStep {
49+
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
50+
apacheHttpRequestStep(n1, n2) or
51+
createUriStep(n1, n2) or
52+
createUrlStep(n1, n2) or
53+
urlOpenStep(n1, n2)
54+
}
55+
}
56+
57+
/** Constructor of `ApacheHttpRequest` */
58+
private predicate apacheHttpRequestStep(DataFlow::Node node1, DataFlow::Node node2) {
59+
exists(ConstructorCall cc |
60+
cc.getConstructedType() instanceof ApacheHttpRequest and
61+
node2.asExpr() = cc and
62+
cc.getAnArgument() = node1.asExpr()
63+
)
64+
}
65+
66+
/** `URI` methods */
67+
private predicate createUriStep(DataFlow::Node node1, DataFlow::Node node2) {
68+
exists(UriConstructorCall cc |
69+
cc.getSchemeArg() = node1.asExpr() and
70+
node2.asExpr() = cc
71+
)
72+
}
73+
74+
/** Constructors of `URL` */
75+
private predicate createUrlStep(DataFlow::Node node1, DataFlow::Node node2) {
76+
exists(UrlConstructorCall cc |
77+
cc.getProtocolArg() = node1.asExpr() and
78+
node2.asExpr() = cc
79+
)
80+
}
81+
82+
/** Method call of `HttpURLOpenMethod` */
83+
private predicate urlOpenStep(DataFlow::Node node1, DataFlow::Node node2) {
84+
exists(MethodAccess ma |
85+
ma.getMethod() instanceof UrlOpenConnectionMethod and
86+
node1.asExpr() = ma.getQualifier() and
87+
ma = node2.asExpr()
88+
)
89+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/** Provides taint tracking configurations to be used in HTTPS URLs queries. */
2+
3+
import java
4+
import semmle.code.java.dataflow.TaintTracking
5+
import semmle.code.java.frameworks.Networking
6+
import semmle.code.java.security.HttpsUrls
7+
8+
/**
9+
* A taint tracking configuration for HTTP connections.
10+
*/
11+
class HttpStringToUrlOpenMethodFlowConfig extends TaintTracking::Configuration {
12+
HttpStringToUrlOpenMethodFlowConfig() { this = "HttpStringToUrlOpenMethodFlowConfig" }
13+
14+
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof HttpStringLiteral }
15+
16+
override predicate isSink(DataFlow::Node sink) { sink instanceof UrlOpenSink }
17+
18+
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
19+
any(HttpUrlsAdditionalTaintStep c).step(node1, node2)
20+
}
21+
22+
override predicate isSanitizer(DataFlow::Node node) {
23+
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
24+
}
25+
}

java/ql/src/Security/CWE/CWE-319/HttpsUrls.ql

Lines changed: 2 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -11,54 +11,10 @@
1111
*/
1212

1313
import java
14-
import semmle.code.java.dataflow.TaintTracking
15-
import semmle.code.java.frameworks.Networking
14+
import semmle.code.java.security.HttpsUrlsQuery
1615
import DataFlow::PathGraph
17-
private import semmle.code.java.dataflow.ExternalFlow
1816

19-
class HttpString extends StringLiteral {
20-
HttpString() {
21-
// Avoid matching "https" here.
22-
exists(string s | this.getRepresentedString() = s |
23-
(
24-
// Either the literal "http", ...
25-
s = "http"
26-
or
27-
// ... or the beginning of a http URL.
28-
s.matches("http://%")
29-
) and
30-
not s.matches("%/localhost%")
31-
)
32-
}
33-
}
34-
35-
class HttpStringToUrlOpenMethodFlowConfig extends TaintTracking::Configuration {
36-
HttpStringToUrlOpenMethodFlowConfig() { this = "HttpsUrls::HttpStringToUrlOpenMethodFlowConfig" }
37-
38-
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof HttpString }
39-
40-
override predicate isSink(DataFlow::Node sink) { sink instanceof UrlOpenSink }
41-
42-
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
43-
exists(UrlConstructorCall u |
44-
node1.asExpr() = u.protocolArg() and
45-
node2.asExpr() = u
46-
)
47-
}
48-
49-
override predicate isSanitizer(DataFlow::Node node) {
50-
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
51-
}
52-
}
53-
54-
/**
55-
* A sink that represents a URL opening method call, such as a call to `java.net.URL.openConnection()`.
56-
*/
57-
private class UrlOpenSink extends DataFlow::Node {
58-
UrlOpenSink() { sinkNode(this, "open-url") }
59-
}
60-
61-
from DataFlow::PathNode source, DataFlow::PathNode sink, MethodAccess m, HttpString s
17+
from DataFlow::PathNode source, DataFlow::PathNode sink, MethodAccess m, HttpStringLiteral s
6218
where
6319
source.getNode().asExpr() = s and
6420
sink.getNode().asExpr() = m.getQualifier() and

0 commit comments

Comments
 (0)