|
11 | 11 | */ |
12 | 12 |
|
13 | 13 | 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 |
82 | 15 | import TrustAllHostnameVerifierFlow::PathGraph |
83 | 16 |
|
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 | | - |
117 | 17 | from |
118 | 18 | TrustAllHostnameVerifierFlow::PathNode source, TrustAllHostnameVerifierFlow::PathNode sink, |
119 | 19 | RefType verifier |
|
0 commit comments