Skip to content
This repository was archived by the owner on Jan 5, 2023. It is now read-only.

Commit 88cb435

Browse files
committed
Split security flags into more distinct categories
There are now three categories: general security or option flags, those related to TLS version selection, and those related to certificate configuration. The TLS and disabled-certificate-check queries use two categories each.
1 parent 3c244e2 commit 88cb435

File tree

3 files changed

+69
-27
lines changed

3 files changed

+69
-27
lines changed

ql/src/Security/CWE-295/DisabledCertificateCheck.ql

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,29 @@ predicate becomesPartOf(DataFlow::Node part, DataFlow::Node whole) {
3636
exists(Write w | w.writesField(whole.(DataFlow::PostUpdateNode).getPreUpdateNode(), _, part))
3737
}
3838

39+
/**
40+
* Holds if `name` is (likely to be) a general security flag or one specifically controlling
41+
* an insecure certificate setup.
42+
*/
43+
bindingset[name]
44+
predicate isSecurityOrCertificateConfigFlag(string name) {
45+
isSecurityFlagName(name) or isCertificateFlagName(name)
46+
}
47+
3948
from Write w, DataFlow::Node base, Field f, DataFlow::Node rhs
4049
where
4150
w.writesField(base, f, rhs) and
4251
f.hasQualifiedName("crypto/tls", "Config", "InsecureSkipVerify") and
4352
rhs.getBoolValue() = true and
4453
// exclude writes guarded by a feature flag
45-
not getAFeatureFlagCheck().dominatesNode(w) and
54+
not [getASecurityFeatureFlagCheck(), getAnInsecureCertificateCheck()].dominatesNode(w) and
4655
// exclude results in functions whose name documents the insecurity
4756
not exists(FuncDef fn | fn = w.getRoot() |
48-
isFeatureFlagName(fn.getEnclosingFunction*().getName())
57+
isSecurityOrCertificateConfigFlag(fn.getEnclosingFunction*().getName())
4958
) and
5059
// exclude results that flow into a field/variable whose name documents the insecurity
5160
not exists(ValueEntity e, DataFlow::Node init |
52-
isFeatureFlagName(e.getName()) and
61+
isSecurityOrCertificateConfigFlag(e.getName()) and
5362
any(Write w2).writes(e, init) and
5463
becomesPartOf*(base, init)
5564
) and

ql/src/experimental/CWE-327/InsecureTLS.ql

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -233,13 +233,14 @@ where
233233
isInsecureTlsCipherFlow(source, sink, message)
234234
) and
235235
// Exclude sources or sinks guarded by a feature or legacy flag
236-
not [getAFeatureFlagCheck(), getALegacyVersionCheck()]
236+
not [getASecurityFeatureFlagCheck(), getALegacyTlsVersionCheck()]
237237
.dominatesNode([source, sink].getNode().asInstruction()) and
238238
// Exclude sources or sinks that occur lexically within a block related to a feature or legacy flag
239-
not astNodeIsFlag([source, sink].getNode().asExpr().getParent*(), [featureFlag(), legacyFlag()]) and
239+
not astNodeIsFlag([source, sink].getNode().asExpr().getParent*(),
240+
[securityFeatureFlag(), legacyTlsVersionFlag()]) and
240241
// Exclude results in functions whose name documents insecurity
241242
not exists(FuncDef fn | fn = sink.getNode().getRoot().getEnclosingFunction*() |
242-
isFeatureFlagName(fn.getName()) or
243-
isLegacyFlagName(fn.getName())
243+
isSecurityFlagName(fn.getName()) or
244+
isLegacyTlsFlagName(fn.getName())
244245
)
245246
select sink.getNode(), source, sink, message

ql/src/semmle/go/security/InsecureFeatureFlag.qll

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,41 @@
55
import go
66

77
module InsecureFeatureFlag {
8+
/**
9+
* Holds if `name` may be the name of a feature flag that controls a security feature.
10+
*/
11+
bindingset[name]
12+
predicate isSecurityFlagName(string name) { name.regexpMatch("(?i).*(secure|(en|dis)able).*") }
13+
814
/**
915
* Holds if `name` may be the name of a feature flag that controls whether certificate checking is
1016
* enabled.
1117
*/
1218
bindingset[name]
13-
predicate isFeatureFlagName(string name) {
14-
name.regexpMatch("(?i).*(secure|selfCert|selfSign|validat|verif|trust|(en|dis)able).*")
19+
predicate isCertificateFlagName(string name) {
20+
name.regexpMatch("(?i).*(selfCert|selfSign|validat|verif|trust).*")
1521
}
1622

1723
/**
18-
* Holds if `name` suggests an old or legacy version.
24+
* Holds if `name` suggests an old or legacy version of TLS.
1925
*
2026
* We accept 'intermediate' because it appears to be common for TLS users
2127
* to define three profiles: modern, intermediate, legacy/old, perhaps based
2228
* on https://wiki.mozilla.org/Security/Server_Side_TLS (though note the
2329
* 'intermediate' used there would now pass muster according to this query)
2430
*/
2531
bindingset[name]
26-
predicate isLegacyFlagName(string name) { name.regexpMatch("(?i).*(old|intermediate|legacy).*") }
32+
predicate isLegacyTlsFlagName(string name) {
33+
name.regexpMatch("(?i).*(old|intermediate|legacy).*")
34+
}
2735

2836
/**
2937
* A kind of flag that may indicate security expectations regarding the code it guards.
3038
*/
3139
abstract class FlagKind extends string {
32-
FlagKind() { this = "feature" or this = "legacy" }
40+
FlagKind() {
41+
this = "securityFeature" or this = "legacyTlsVersion" or this = "insecureCertificate"
42+
}
3343

3444
/**
3545
* Returns a flag name of this type.
@@ -40,32 +50,47 @@ module InsecureFeatureFlag {
4050
/**
4151
* Flags suggesting an optional feature, perhaps deliberately insecure.
4252
*/
43-
class FeatureFlag extends FlagKind {
44-
FeatureFlag() { this = "feature" }
53+
class SecurityFeatureFlag extends FlagKind {
54+
SecurityFeatureFlag() { this = "securityFeature" }
4555

4656
bindingset[result]
47-
override string getAFlagName() { isFeatureFlagName(result) }
57+
override string getAFlagName() { isSecurityFlagName(result) }
4858
}
4959

5060
/**
5161
* Flags suggesting an optional feature, perhaps deliberately insecure.
5262
*/
53-
string featureFlag() { result = "feature" }
63+
string securityFeatureFlag() { result = "securityFeature" }
5464

5565
/**
56-
* Flags suggesting support for an old or legacy feature.
66+
* Flags suggesting support for an old or legacy TLS version.
5767
*/
58-
class LegacyFlag extends FlagKind {
59-
LegacyFlag() { this = "legacy" }
68+
class LegacyTlsVersionFlag extends FlagKind {
69+
LegacyTlsVersionFlag() { this = "legacyTlsVersion" }
6070

6171
bindingset[result]
62-
override string getAFlagName() { isLegacyFlagName(result) }
72+
override string getAFlagName() { isLegacyTlsFlagName(result) }
73+
}
74+
75+
/**
76+
* Flags suggesting support for an old or legacy TLS version.
77+
*/
78+
string legacyTlsVersionFlag() { result = "legacyTlsVersion" }
79+
80+
/**
81+
* Flags suggesting a deliberately insecure certificate setup.
82+
*/
83+
class InsecureCertificateFlag extends FlagKind {
84+
InsecureCertificateFlag() { this = "insecureCertificate" }
85+
86+
bindingset[result]
87+
override string getAFlagName() { isCertificateFlagName(result) }
6388
}
6489

6590
/**
6691
* Flags suggesting support for an old or legacy feature.
6792
*/
68-
string legacyFlag() { result = "legacy" }
93+
string insecureCertificateFlag() { result = "insecureCertificate" }
6994

7095
/** Gets a global value number representing a (likely) security flag. */
7196
GVN getAFlag(FlagKind flagKind) {
@@ -149,16 +174,23 @@ module InsecureFeatureFlag {
149174
}
150175

151176
/**
152-
* Gets a control-flow node that represents a (likely) feature-flag check for certificate checking.
177+
* Gets a control-flow node that represents a (likely) security feature-flag check
178+
*/
179+
ControlFlow::ConditionGuardNode getASecurityFeatureFlagCheck() {
180+
result.ensures(getAFlag(securityFeatureFlag()).getANode(), _)
181+
}
182+
183+
/**
184+
* Gets a control-flow node that represents a (likely) flag controlling TLS version selection.
153185
*/
154-
ControlFlow::ConditionGuardNode getAFeatureFlagCheck() {
155-
result.ensures(getAFlag(featureFlag()).getANode(), _)
186+
ControlFlow::ConditionGuardNode getALegacyTlsVersionCheck() {
187+
result.ensures(getAFlag(legacyTlsVersionFlag()).getANode(), _)
156188
}
157189

158190
/**
159-
* Gets a control-flow node that represents a (likely) feature-flag check for certificate checking.
191+
* Gets a control-flow node that represents a (likely) flag controlling an insecure certificate setup.
160192
*/
161-
ControlFlow::ConditionGuardNode getALegacyVersionCheck() {
162-
result.ensures(getAFlag(legacyFlag()).getANode(), _)
193+
ControlFlow::ConditionGuardNode getAnInsecureCertificateCheck() {
194+
result.ensures(getAFlag(insecureCertificateFlag()).getANode(), _)
163195
}
164196
}

0 commit comments

Comments
 (0)