Skip to content

Commit 24b00ba

Browse files
committed
Add UnsafeHostnameVerificationQuery
1 parent f4a6f55 commit 24b00ba

File tree

3 files changed

+107
-102
lines changed

3 files changed

+107
-102
lines changed

java/ql/lib/change-notes/2023-03-30-add-libraries-for-query-configurations.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ category: minorAnalysis
1010
* Added the `ExecTaintedLocalQuery.qll` library to provide the `LocalUserInputToArgumentToExecFlow` taint-tracking module to reason about command injection vulnerabilities caused by local data flow.
1111
* Added the `StackTraceExposureQuery.qll` library to provide the `printsStackExternally`, `stringifiedStackFlowsExternally`, and `getMessageFlowsExternally` predicates to reason about stack trace exposure vulnerabilities.
1212
* Added the `SqlTaintedLocalQuery.qll` library to provide the `LocalUserInputToArgumentToSqlFlow` taint-tracking module to reason about SQL injection vulnerabilities caused by local data flow.
13-
* Added the `ResponseSplittingLocalQuery.qll` library to provide the `ResponseSplittingLocalFlow` taint-tracking module to reason about response splitting vulnerabilities caused by local data flow.
13+
* Added the `ResponseSplittingLocalQuery.qll` library to provide the `ResponseSplittingLocalFlow` taint-tracking module to reason about response splitting vulnerabilities caused by local data flow.
14+
* Added the `UnsafeHostnameVerificationQuery.qll` library to provide the `TrustAllHostnameVerifierFlow` taint-tracking module to reason about insecure hostname verification vulnerabilities.
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/** Provides predicates and dataflow configurations for reasoning about unsafe hostname verification. */
2+
3+
import java
4+
private import semmle.code.java.controlflow.Guards
5+
private import semmle.code.java.dataflow.DataFlow
6+
private import semmle.code.java.dataflow.FlowSources
7+
private import semmle.code.java.security.Encryption
8+
private import semmle.code.java.security.SecurityFlag
9+
private import semmle.code.java.dataflow.ExternalFlow
10+
11+
/**
12+
* Holds if `m` always returns `true` ignoring any exceptional flow.
13+
*/
14+
private predicate alwaysReturnsTrue(HostnameVerifierVerify m) {
15+
forex(ReturnStmt rs | rs.getEnclosingCallable() = m |
16+
rs.getResult().(CompileTimeConstantExpr).getBooleanValue() = true
17+
)
18+
}
19+
20+
/**
21+
* A class that overrides the `javax.net.ssl.HostnameVerifier.verify` method and **always** returns `true` (though it could also exit due to an uncaught exception), thus
22+
* accepting any certificate despite a hostname mismatch.
23+
*/
24+
class TrustAllHostnameVerifier extends RefType {
25+
TrustAllHostnameVerifier() {
26+
this.getAnAncestor() instanceof HostnameVerifier and
27+
exists(HostnameVerifierVerify m |
28+
m.getDeclaringType() = this and
29+
alwaysReturnsTrue(m)
30+
)
31+
}
32+
}
33+
34+
/**
35+
* A configuration to model the flow of a `TrustAllHostnameVerifier` to a `set(Default)HostnameVerifier` call.
36+
*/
37+
module TrustAllHostnameVerifierConfig implements DataFlow::ConfigSig {
38+
predicate isSource(DataFlow::Node source) {
39+
source.asExpr().(ClassInstanceExpr).getConstructedType() instanceof TrustAllHostnameVerifier
40+
}
41+
42+
predicate isSink(DataFlow::Node sink) { sink instanceof HostnameVerifierSink }
43+
44+
predicate isBarrier(DataFlow::Node barrier) {
45+
// ignore nodes that are in functions that intentionally disable hostname verification
46+
barrier
47+
.getEnclosingCallable()
48+
.getName()
49+
/*
50+
* Regex: (_)* :
51+
* some methods have underscores.
52+
* Regex: (no|ignore|disable)(strictssl|ssl|verify|verification|hostname)
53+
* noStrictSSL ignoreSsl
54+
* Regex: (set)?(accept|trust|ignore|allow)(all|every|any)
55+
* acceptAll trustAll ignoreAll setTrustAnyHttps
56+
* Regex: (use|do|enable)insecure
57+
* useInsecureSSL
58+
* Regex: (set|do|use)?no.*(check|validation|verify|verification)
59+
* setNoCertificateCheck
60+
* Regex: disable
61+
* disableChecks
62+
*/
63+
64+
.regexpMatch("^(?i)(_)*((no|ignore|disable)(strictssl|ssl|verify|verification|hostname)" +
65+
"|(set)?(accept|trust|ignore|allow)(all|every|any)" +
66+
"|(use|do|enable)insecure|(set|do|use)?no.*(check|validation|verify|verification)|disable).*$")
67+
}
68+
}
69+
70+
/** Data flow to model the flow of a `TrustAllHostnameVerifier` to a `set(Default)HostnameVerifier` call. */
71+
module TrustAllHostnameVerifierFlow = DataFlow::Global<TrustAllHostnameVerifierConfig>;
72+
73+
/**
74+
* A sink that sets the `HostnameVerifier` on `HttpsURLConnection`.
75+
*/
76+
private class HostnameVerifierSink extends DataFlow::Node {
77+
HostnameVerifierSink() { sinkNode(this, "set-hostname-verifier") }
78+
}
79+
80+
/**
81+
* Flags suggesting a deliberately unsafe `HostnameVerifier` usage.
82+
*/
83+
private class UnsafeHostnameVerificationFlag extends FlagKind {
84+
UnsafeHostnameVerificationFlag() { this = "UnsafeHostnameVerificationFlag" }
85+
86+
bindingset[result]
87+
override string getAFlagName() {
88+
result
89+
.regexpMatch("(?i).*(secure|disable|selfCert|selfSign|validat|verif|trust|ignore|nocertificatecheck).*") and
90+
result != "equalsIgnoreCase"
91+
}
92+
}
93+
94+
/** Gets a guard that represents a (likely) flag controlling an unsafe `HostnameVerifier` use. */
95+
private Guard getAnUnsafeHostnameVerifierFlagGuard() {
96+
result = any(UnsafeHostnameVerificationFlag flag).getAFlag().asExpr()
97+
}
98+
99+
/** Holds if `node` is guarded by a flag that suggests an intentionally insecure use. */
100+
predicate isNodeGuardedByFlag(DataFlow::Node node) {
101+
exists(Guard g | g.controls(node.asExpr().getBasicBlock(), _) |
102+
g = getASecurityFeatureFlagGuard() or g = getAnUnsafeHostnameVerifierFlagGuard()
103+
)
104+
}

java/ql/src/Security/CWE/CWE-297/UnsafeHostnameVerification.ql

Lines changed: 1 addition & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -11,109 +11,9 @@
1111
*/
1212

1313
import java
14-
import semmle.code.java.controlflow.Guards
15-
import semmle.code.java.dataflow.DataFlow
16-
import semmle.code.java.dataflow.FlowSources
17-
import semmle.code.java.security.Encryption
18-
import semmle.code.java.security.SecurityFlag
19-
private import semmle.code.java.dataflow.ExternalFlow
20-
21-
/**
22-
* Holds if `m` always returns `true` ignoring any exceptional flow.
23-
*/
24-
private predicate alwaysReturnsTrue(HostnameVerifierVerify m) {
25-
forex(ReturnStmt rs | rs.getEnclosingCallable() = m |
26-
rs.getResult().(CompileTimeConstantExpr).getBooleanValue() = true
27-
)
28-
}
29-
30-
/**
31-
* A class that overrides the `javax.net.ssl.HostnameVerifier.verify` method and **always** returns `true` (though it could also exit due to an uncaught exception), thus
32-
* accepting any certificate despite a hostname mismatch.
33-
*/
34-
class TrustAllHostnameVerifier extends RefType {
35-
TrustAllHostnameVerifier() {
36-
this.getAnAncestor() instanceof HostnameVerifier and
37-
exists(HostnameVerifierVerify m |
38-
m.getDeclaringType() = this and
39-
alwaysReturnsTrue(m)
40-
)
41-
}
42-
}
43-
44-
/**
45-
* A configuration to model the flow of a `TrustAllHostnameVerifier` to a `set(Default)HostnameVerifier` call.
46-
*/
47-
module TrustAllHostnameVerifierConfig implements DataFlow::ConfigSig {
48-
predicate isSource(DataFlow::Node source) {
49-
source.asExpr().(ClassInstanceExpr).getConstructedType() instanceof TrustAllHostnameVerifier
50-
}
51-
52-
predicate isSink(DataFlow::Node sink) { sink instanceof HostnameVerifierSink }
53-
54-
predicate isBarrier(DataFlow::Node barrier) {
55-
// ignore nodes that are in functions that intentionally disable hostname verification
56-
barrier
57-
.getEnclosingCallable()
58-
.getName()
59-
/*
60-
* Regex: (_)* :
61-
* some methods have underscores.
62-
* Regex: (no|ignore|disable)(strictssl|ssl|verify|verification|hostname)
63-
* noStrictSSL ignoreSsl
64-
* Regex: (set)?(accept|trust|ignore|allow)(all|every|any)
65-
* acceptAll trustAll ignoreAll setTrustAnyHttps
66-
* Regex: (use|do|enable)insecure
67-
* useInsecureSSL
68-
* Regex: (set|do|use)?no.*(check|validation|verify|verification)
69-
* setNoCertificateCheck
70-
* Regex: disable
71-
* disableChecks
72-
*/
73-
74-
.regexpMatch("^(?i)(_)*((no|ignore|disable)(strictssl|ssl|verify|verification|hostname)" +
75-
"|(set)?(accept|trust|ignore|allow)(all|every|any)" +
76-
"|(use|do|enable)insecure|(set|do|use)?no.*(check|validation|verify|verification)|disable).*$")
77-
}
78-
}
79-
80-
module TrustAllHostnameVerifierFlow = DataFlow::Global<TrustAllHostnameVerifierConfig>;
81-
14+
import semmle.code.java.security.UnsafeHostnameVerificationQuery
8215
import TrustAllHostnameVerifierFlow::PathGraph
8316

84-
/**
85-
* A sink that sets the `HostnameVerifier` on `HttpsURLConnection`.
86-
*/
87-
private class HostnameVerifierSink extends DataFlow::Node {
88-
HostnameVerifierSink() { sinkNode(this, "set-hostname-verifier") }
89-
}
90-
91-
/**
92-
* Flags suggesting a deliberately unsafe `HostnameVerifier` usage.
93-
*/
94-
private class UnsafeHostnameVerificationFlag extends FlagKind {
95-
UnsafeHostnameVerificationFlag() { this = "UnsafeHostnameVerificationFlag" }
96-
97-
bindingset[result]
98-
override string getAFlagName() {
99-
result
100-
.regexpMatch("(?i).*(secure|disable|selfCert|selfSign|validat|verif|trust|ignore|nocertificatecheck).*") and
101-
result != "equalsIgnoreCase"
102-
}
103-
}
104-
105-
/** Gets a guard that represents a (likely) flag controlling an unsafe `HostnameVerifier` use. */
106-
private Guard getAnUnsafeHostnameVerifierFlagGuard() {
107-
result = any(UnsafeHostnameVerificationFlag flag).getAFlag().asExpr()
108-
}
109-
110-
/** Holds if `node` is guarded by a flag that suggests an intentionally insecure use. */
111-
private predicate isNodeGuardedByFlag(DataFlow::Node node) {
112-
exists(Guard g | g.controls(node.asExpr().getBasicBlock(), _) |
113-
g = getASecurityFeatureFlagGuard() or g = getAnUnsafeHostnameVerifierFlagGuard()
114-
)
115-
}
116-
11717
from
11818
TrustAllHostnameVerifierFlow::PathNode source, TrustAllHostnameVerifierFlow::PathNode sink,
11919
RefType verifier

0 commit comments

Comments
 (0)