Skip to content

Commit 8756c03

Browse files
committed
C#: Re-factor the InappropriateEncoding query to use the new API.
1 parent feb3161 commit 8756c03

File tree

1 file changed

+73
-51
lines changed

1 file changed

+73
-51
lines changed

csharp/ql/src/Security Features/CWE-838/InappropriateEncoding.ql

Lines changed: 73 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -20,57 +20,47 @@ import semmle.code.csharp.security.dataflow.SqlInjectionQuery as SqlInjection
2020
import semmle.code.csharp.security.dataflow.flowsinks.Html
2121
import semmle.code.csharp.security.dataflow.UrlRedirectQuery as UrlRedirect
2222
import semmle.code.csharp.security.Sanitizers
23-
import semmle.code.csharp.dataflow.DataFlow2::DataFlow2
24-
import semmle.code.csharp.dataflow.DataFlow2::DataFlow2::PathGraph
25-
import semmle.code.csharp.dataflow.TaintTracking2
23+
import EncodingConfigurations::Flow::PathGraph
24+
25+
signature module EncodingConfigSig {
26+
/** Holds if `n` is a node whose value must be encoded. */
27+
predicate requiresEncoding(DataFlow::Node n);
28+
29+
/** Holds if `e` is a possible valid encoded value. */
30+
predicate isPossibleEncodedValue(Expr e);
31+
}
2632

2733
/**
2834
* A configuration for specifying expressions that must be
2935
* encoded, along with a set of potential valid encoded values.
3036
*/
31-
abstract class RequiresEncodingConfiguration extends TaintTracking2::Configuration {
32-
bindingset[this]
33-
RequiresEncodingConfiguration() { any() }
34-
35-
/** Gets a textual representation of this kind of encoding requirement. */
36-
abstract string getKind();
37-
38-
/** Holds if `e` is an expression whose value must be encoded. */
39-
abstract predicate requiresEncoding(Node n);
40-
41-
/** Holds if `e` is a possible valid encoded value. */
42-
predicate isPossibleEncodedValue(Expr e) { none() }
43-
44-
/**
45-
* Holds if `encodedValue` is a possibly ill-encoded value that reaches
46-
* `sink`, where `sink` is an expression of kind `kind` that is required
47-
* to be encoded.
48-
*/
49-
predicate hasWrongEncoding(PathNode encodedValue, PathNode sink, string kind) {
50-
this.hasFlowPath(encodedValue, sink) and
51-
kind = this.getKind()
52-
}
53-
54-
override predicate isSource(Node source) {
37+
module RequiresEncodingConfig<EncodingConfigSig EncodingConfig> implements DataFlow::ConfigSig {
38+
predicate isSource(DataFlow::Node source) {
5539
// all encoded values that do not match this configuration are
5640
// considered sources
5741
exists(Expr e | e = source.asExpr() |
5842
e instanceof EncodedValue and
59-
not this.isPossibleEncodedValue(e)
43+
not EncodingConfig::isPossibleEncodedValue(e)
6044
)
6145
}
6246

63-
override predicate isSink(Node sink) { this.requiresEncoding(sink) }
47+
predicate isSink(DataFlow::Node sink) { EncodingConfig::requiresEncoding(sink) }
6448

65-
override predicate isSanitizer(Node sanitizer) { this.isPossibleEncodedValue(sanitizer.asExpr()) }
49+
predicate isBarrier(DataFlow::Node sanitizer) {
50+
EncodingConfig::isPossibleEncodedValue(sanitizer.asExpr())
51+
}
6652

67-
override int fieldFlowBranchLimit() { result = 0 }
53+
int fieldFlowBranchLimit() { result = 0 }
6854
}
6955

7056
/** An encoded value, for example a call to `HttpServerUtility.HtmlEncode`. */
7157
class EncodedValue extends Expr {
7258
EncodedValue() {
73-
any(RequiresEncodingConfiguration c).isPossibleEncodedValue(this)
59+
EncodingConfigurations::SqlExprEncodingConfig::isPossibleEncodedValue(this)
60+
or
61+
EncodingConfigurations::HtmlExprEncodingConfig::isPossibleEncodedValue(this)
62+
or
63+
EncodingConfigurations::UrlExprEncodingConfig::isPossibleEncodedValue(this)
7464
or
7565
this = any(SystemWebHttpUtility c).getAJavaScriptStringEncodeMethod().getACall()
7666
or
@@ -86,18 +76,20 @@ class EncodedValue extends Expr {
8676
}
8777

8878
module EncodingConfigurations {
89-
/** An encoding configuration for SQL expressions. */
90-
class SqlExpr extends RequiresEncodingConfiguration {
91-
SqlExpr() { this = "SqlExpr" }
79+
module SqlExprEncodingConfig implements EncodingConfigSig {
80+
predicate requiresEncoding(DataFlow::Node n) { n instanceof SqlInjection::Sink }
9281

93-
override string getKind() { result = "SQL expression" }
82+
predicate isPossibleEncodedValue(Expr e) { none() }
83+
}
9484

95-
override predicate requiresEncoding(Node n) { n instanceof SqlInjection::Sink }
85+
/** An encoding configuration for SQL expressions. */
86+
module SqlExprConfig implements DataFlow::ConfigSig {
87+
import RequiresEncodingConfig<SqlExprEncodingConfig> as Super
9688

9789
// no override for `isPossibleEncodedValue` as SQL parameters should
9890
// be used instead of explicit encoding
99-
override predicate isSource(Node source) {
100-
super.isSource(source)
91+
predicate isSource(DataFlow::Node source) {
92+
Super::isSource(source)
10193
or
10294
// consider quote-replacing calls as additional sources for
10395
// SQL expressions (e.g., `s.Replace("\"", "\"\"")`)
@@ -107,32 +99,62 @@ module EncodingConfigurations {
10799
mc.getArgument(0).getValue().regexpMatch("\"|'|`")
108100
)
109101
}
102+
103+
predicate isSink = Super::isSink/1;
104+
105+
predicate isBarrier = Super::isBarrier/1;
106+
107+
int fieldFlowBranchLimit() { result = Super::fieldFlowBranchLimit() }
108+
}
109+
110+
module SqlExpr = TaintTracking::Global<SqlExprConfig>;
111+
112+
module HtmlExprEncodingConfig implements EncodingConfigSig {
113+
predicate requiresEncoding(DataFlow::Node n) { n instanceof HtmlSink }
114+
115+
predicate isPossibleEncodedValue(Expr e) { e instanceof HtmlSanitizedExpr }
110116
}
111117

112118
/** An encoding configuration for HTML expressions. */
113-
class HtmlExpr extends RequiresEncodingConfiguration {
114-
HtmlExpr() { this = "HtmlExpr" }
119+
module HtmlExprConfig = RequiresEncodingConfig<HtmlExprEncodingConfig>;
115120

116-
override string getKind() { result = "HTML expression" }
121+
module HtmlExpr = TaintTracking::Global<HtmlExprConfig>;
117122

118-
override predicate requiresEncoding(Node n) { n instanceof HtmlSink }
123+
module UrlExprEncodingConfig implements EncodingConfigSig {
124+
predicate requiresEncoding(DataFlow::Node n) { n instanceof UrlRedirect::Sink }
119125

120-
override predicate isPossibleEncodedValue(Expr e) { e instanceof HtmlSanitizedExpr }
126+
predicate isPossibleEncodedValue(Expr e) { e instanceof UrlSanitizedExpr }
121127
}
122128

123129
/** An encoding configuration for URL expressions. */
124-
class UrlExpr extends RequiresEncodingConfiguration {
125-
UrlExpr() { this = "UrlExpr" }
130+
module UrlExprConfig = RequiresEncodingConfig<UrlExprEncodingConfig>;
126131

127-
override string getKind() { result = "URL expression" }
132+
module UrlExpr = TaintTracking::Global<UrlExprConfig>;
128133

129-
override predicate requiresEncoding(Node n) { n instanceof UrlRedirect::Sink }
134+
module Flow =
135+
DataFlow::MergePathGraph3<SqlExpr::PathNode, HtmlExpr::PathNode, UrlExpr::PathNode,
136+
SqlExpr::PathGraph, HtmlExpr::PathGraph, UrlExpr::PathGraph>;
130137

131-
override predicate isPossibleEncodedValue(Expr e) { e instanceof UrlSanitizedExpr }
138+
/**
139+
* Holds if `encodedValue` is a possibly ill-encoded value that reaches
140+
* `sink`, where `sink` is an expression of kind `kind` that is required
141+
* to be encoded.
142+
*/
143+
predicate hasWrongEncoding(Flow::PathNode encodedValue, Flow::PathNode sink, string kind) {
144+
SqlExpr::flowPath(encodedValue.asPathNode1(), sink.asPathNode1()) and
145+
kind = "SQL expression"
146+
or
147+
HtmlExpr::flowPath(encodedValue.asPathNode2(), sink.asPathNode2()) and
148+
kind = "HTML expression"
149+
or
150+
UrlExpr::flowPath(encodedValue.asPathNode3(), sink.asPathNode3()) and
151+
kind = "URL expression"
132152
}
133153
}
134154

135-
from RequiresEncodingConfiguration c, PathNode encodedValue, PathNode sink, string kind
136-
where c.hasWrongEncoding(encodedValue, sink, kind)
155+
from
156+
EncodingConfigurations::Flow::PathNode encodedValue, EncodingConfigurations::Flow::PathNode sink,
157+
string kind
158+
where EncodingConfigurations::hasWrongEncoding(encodedValue, sink, kind)
137159
select sink.getNode(), encodedValue, sink, "This " + kind + " may include data from a $@.",
138160
encodedValue.getNode(), "possibly inappropriately encoded value"

0 commit comments

Comments
 (0)