@@ -20,57 +20,46 @@ import semmle.code.csharp.security.dataflow.SqlInjectionQuery as SqlInjection
20
20
import semmle.code.csharp.security.dataflow.flowsinks.Html
21
21
import semmle.code.csharp.security.dataflow.UrlRedirectQuery as UrlRedirect
22
22
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
26
24
27
- /**
28
- * A configuration for specifying expressions that must be
29
- * encoded, along with a set of potential valid encoded values.
30
- */
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 ) ;
25
+ signature module EncodingConfigSig {
26
+ /** Holds if `n` is a node whose value must be encoded. */
27
+ predicate requiresEncoding ( DataFlow:: Node n ) ;
40
28
41
29
/** 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
- }
30
+ predicate isPossibleEncodedValue ( Expr e ) ;
31
+ }
53
32
54
- override predicate isSource ( Node source ) {
33
+ /**
34
+ * A configuration for specifying expressions that must be encoded.
35
+ */
36
+ module RequiresEncodingConfig< EncodingConfigSig EncodingConfig> implements DataFlow:: ConfigSig {
37
+ predicate isSource ( DataFlow:: Node source ) {
55
38
// all encoded values that do not match this configuration are
56
39
// considered sources
57
40
exists ( Expr e | e = source .asExpr ( ) |
58
41
e instanceof EncodedValue and
59
- not this . isPossibleEncodedValue ( e )
42
+ not EncodingConfig :: isPossibleEncodedValue ( e )
60
43
)
61
44
}
62
45
63
- override predicate isSink ( Node sink ) { this . requiresEncoding ( sink ) }
46
+ predicate isSink ( DataFlow :: Node sink ) { EncodingConfig :: requiresEncoding ( sink ) }
64
47
65
- override predicate isSanitizer ( Node sanitizer ) { this .isPossibleEncodedValue ( sanitizer .asExpr ( ) ) }
48
+ predicate isBarrier ( DataFlow:: Node sanitizer ) {
49
+ EncodingConfig:: isPossibleEncodedValue ( sanitizer .asExpr ( ) )
50
+ }
66
51
67
- override int fieldFlowBranchLimit ( ) { result = 0 }
52
+ int fieldFlowBranchLimit ( ) { result = 0 }
68
53
}
69
54
70
- /** An encoded value, for example a call to `HttpServerUtility.HtmlEncode`. */
55
+ /** An encoded value, for example through a call to `HttpServerUtility.HtmlEncode`. */
71
56
class EncodedValue extends Expr {
72
57
EncodedValue ( ) {
73
- any ( RequiresEncodingConfiguration c ) .isPossibleEncodedValue ( this )
58
+ EncodingConfigurations:: SqlExprEncodingConfig:: isPossibleEncodedValue ( this )
59
+ or
60
+ EncodingConfigurations:: HtmlExprEncodingConfig:: isPossibleEncodedValue ( this )
61
+ or
62
+ EncodingConfigurations:: UrlExprEncodingConfig:: isPossibleEncodedValue ( this )
74
63
or
75
64
this = any ( SystemWebHttpUtility c ) .getAJavaScriptStringEncodeMethod ( ) .getACall ( )
76
65
or
@@ -86,18 +75,20 @@ class EncodedValue extends Expr {
86
75
}
87
76
88
77
module EncodingConfigurations {
89
- /** An encoding configuration for SQL expressions. */
90
- class SqlExpr extends RequiresEncodingConfiguration {
91
- SqlExpr ( ) { this = "SqlExpr" }
78
+ module SqlExprEncodingConfig implements EncodingConfigSig {
79
+ predicate requiresEncoding ( DataFlow:: Node n ) { n instanceof SqlInjection:: Sink }
92
80
93
- override string getKind ( ) { result = "SQL expression" }
81
+ predicate isPossibleEncodedValue ( Expr e ) { none ( ) }
82
+ }
94
83
95
- override predicate requiresEncoding ( Node n ) { n instanceof SqlInjection:: Sink }
84
+ /** An encoding configuration for SQL expressions. */
85
+ module SqlExprConfig implements DataFlow:: ConfigSig {
86
+ import RequiresEncodingConfig< SqlExprEncodingConfig > as Super
96
87
97
88
// no override for `isPossibleEncodedValue` as SQL parameters should
98
89
// be used instead of explicit encoding
99
- override predicate isSource ( Node source ) {
100
- super . isSource ( source )
90
+ predicate isSource ( DataFlow :: Node source ) {
91
+ Super :: isSource ( source )
101
92
or
102
93
// consider quote-replacing calls as additional sources for
103
94
// SQL expressions (e.g., `s.Replace("\"", "\"\"")`)
@@ -107,32 +98,62 @@ module EncodingConfigurations {
107
98
mc .getArgument ( 0 ) .getValue ( ) .regexpMatch ( "\"|'|`" )
108
99
)
109
100
}
101
+
102
+ predicate isSink = Super:: isSink / 1 ;
103
+
104
+ predicate isBarrier = Super:: isBarrier / 1 ;
105
+
106
+ int fieldFlowBranchLimit ( ) { result = Super:: fieldFlowBranchLimit ( ) }
107
+ }
108
+
109
+ module SqlExpr = TaintTracking:: Global< SqlExprConfig > ;
110
+
111
+ module HtmlExprEncodingConfig implements EncodingConfigSig {
112
+ predicate requiresEncoding ( DataFlow:: Node n ) { n instanceof HtmlSink }
113
+
114
+ predicate isPossibleEncodedValue ( Expr e ) { e instanceof HtmlSanitizedExpr }
110
115
}
111
116
112
117
/** An encoding configuration for HTML expressions. */
113
- class HtmlExpr extends RequiresEncodingConfiguration {
114
- HtmlExpr ( ) { this = "HtmlExpr" }
118
+ module HtmlExprConfig = RequiresEncodingConfig< HtmlExprEncodingConfig > ;
115
119
116
- override string getKind ( ) { result = "HTML expression" }
120
+ module HtmlExpr = TaintTracking :: Global < HtmlExprConfig > ;
117
121
118
- override predicate requiresEncoding ( Node n ) { n instanceof HtmlSink }
122
+ module UrlExprEncodingConfig implements EncodingConfigSig {
123
+ predicate requiresEncoding ( DataFlow:: Node n ) { n instanceof UrlRedirect:: Sink }
119
124
120
- override predicate isPossibleEncodedValue ( Expr e ) { e instanceof HtmlSanitizedExpr }
125
+ predicate isPossibleEncodedValue ( Expr e ) { e instanceof UrlSanitizedExpr }
121
126
}
122
127
123
128
/** An encoding configuration for URL expressions. */
124
- class UrlExpr extends RequiresEncodingConfiguration {
125
- UrlExpr ( ) { this = "UrlExpr" }
129
+ module UrlExprConfig = RequiresEncodingConfig< UrlExprEncodingConfig > ;
126
130
127
- override string getKind ( ) { result = "URL expression" }
131
+ module UrlExpr = TaintTracking :: Global < UrlExprConfig > ;
128
132
129
- override predicate requiresEncoding ( Node n ) { n instanceof UrlRedirect:: Sink }
133
+ module Flow =
134
+ DataFlow:: MergePathGraph3< SqlExpr:: PathNode , HtmlExpr:: PathNode , UrlExpr:: PathNode ,
135
+ SqlExpr:: PathGraph , HtmlExpr:: PathGraph , UrlExpr:: PathGraph > ;
130
136
131
- override predicate isPossibleEncodedValue ( Expr e ) { e instanceof UrlSanitizedExpr }
137
+ /**
138
+ * Holds if `encodedValue` is a possibly ill-encoded value that reaches
139
+ * `sink`, where `sink` is an expression of kind `kind` that is required
140
+ * to be encoded.
141
+ */
142
+ predicate hasWrongEncoding ( Flow:: PathNode encodedValue , Flow:: PathNode sink , string kind ) {
143
+ SqlExpr:: flowPath ( encodedValue .asPathNode1 ( ) , sink .asPathNode1 ( ) ) and
144
+ kind = "SQL expression"
145
+ or
146
+ HtmlExpr:: flowPath ( encodedValue .asPathNode2 ( ) , sink .asPathNode2 ( ) ) and
147
+ kind = "HTML expression"
148
+ or
149
+ UrlExpr:: flowPath ( encodedValue .asPathNode3 ( ) , sink .asPathNode3 ( ) ) and
150
+ kind = "URL expression"
132
151
}
133
152
}
134
153
135
- from RequiresEncodingConfiguration c , PathNode encodedValue , PathNode sink , string kind
136
- where c .hasWrongEncoding ( encodedValue , sink , kind )
154
+ from
155
+ EncodingConfigurations:: Flow:: PathNode encodedValue , EncodingConfigurations:: Flow:: PathNode sink ,
156
+ string kind
157
+ where EncodingConfigurations:: hasWrongEncoding ( encodedValue , sink , kind )
137
158
select sink .getNode ( ) , encodedValue , sink , "This " + kind + " may include data from a $@." ,
138
159
encodedValue .getNode ( ) , "possibly inappropriately encoded value"
0 commit comments