@@ -20,57 +20,46 @@ import semmle.code.csharp.security.dataflow.SqlInjectionQuery as SqlInjection
2020import semmle.code.csharp.security.dataflow.flowsinks.Html
2121import semmle.code.csharp.security.dataflow.UrlRedirectQuery as UrlRedirect
2222import 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
2624
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 ) ;
4028
4129 /** 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+ }
5332
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 ) {
5538 // all encoded values that do not match this configuration are
5639 // considered sources
5740 exists ( Expr e | e = source .asExpr ( ) |
5841 e instanceof EncodedValue and
59- not this . isPossibleEncodedValue ( e )
42+ not EncodingConfig :: isPossibleEncodedValue ( e )
6043 )
6144 }
6245
63- override predicate isSink ( Node sink ) { this . requiresEncoding ( sink ) }
46+ predicate isSink ( DataFlow :: Node sink ) { EncodingConfig :: requiresEncoding ( sink ) }
6447
65- override predicate isSanitizer ( Node sanitizer ) { this .isPossibleEncodedValue ( sanitizer .asExpr ( ) ) }
48+ predicate isBarrier ( DataFlow:: Node sanitizer ) {
49+ EncodingConfig:: isPossibleEncodedValue ( sanitizer .asExpr ( ) )
50+ }
6651
67- override int fieldFlowBranchLimit ( ) { result = 0 }
52+ int fieldFlowBranchLimit ( ) { result = 0 }
6853}
6954
70- /** An encoded value, for example a call to `HttpServerUtility.HtmlEncode`. */
55+ /** An encoded value, for example through a call to `HttpServerUtility.HtmlEncode`. */
7156class EncodedValue extends Expr {
7257 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 )
7463 or
7564 this = any ( SystemWebHttpUtility c ) .getAJavaScriptStringEncodeMethod ( ) .getACall ( )
7665 or
@@ -86,18 +75,20 @@ class EncodedValue extends Expr {
8675}
8776
8877module 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 }
9280
93- override string getKind ( ) { result = "SQL expression" }
81+ predicate isPossibleEncodedValue ( Expr e ) { none ( ) }
82+ }
9483
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
9687
9788 // no override for `isPossibleEncodedValue` as SQL parameters should
9889 // 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 )
10192 or
10293 // consider quote-replacing calls as additional sources for
10394 // SQL expressions (e.g., `s.Replace("\"", "\"\"")`)
@@ -107,32 +98,62 @@ module EncodingConfigurations {
10798 mc .getArgument ( 0 ) .getValue ( ) .regexpMatch ( "\"|'|`" )
10899 )
109100 }
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 }
110115 }
111116
112117 /** An encoding configuration for HTML expressions. */
113- class HtmlExpr extends RequiresEncodingConfiguration {
114- HtmlExpr ( ) { this = "HtmlExpr" }
118+ module HtmlExprConfig = RequiresEncodingConfig< HtmlExprEncodingConfig > ;
115119
116- override string getKind ( ) { result = "HTML expression" }
120+ module HtmlExpr = TaintTracking :: Global < HtmlExprConfig > ;
117121
118- override predicate requiresEncoding ( Node n ) { n instanceof HtmlSink }
122+ module UrlExprEncodingConfig implements EncodingConfigSig {
123+ predicate requiresEncoding ( DataFlow:: Node n ) { n instanceof UrlRedirect:: Sink }
119124
120- override predicate isPossibleEncodedValue ( Expr e ) { e instanceof HtmlSanitizedExpr }
125+ predicate isPossibleEncodedValue ( Expr e ) { e instanceof UrlSanitizedExpr }
121126 }
122127
123128 /** An encoding configuration for URL expressions. */
124- class UrlExpr extends RequiresEncodingConfiguration {
125- UrlExpr ( ) { this = "UrlExpr" }
129+ module UrlExprConfig = RequiresEncodingConfig< UrlExprEncodingConfig > ;
126130
127- override string getKind ( ) { result = "URL expression" }
131+ module UrlExpr = TaintTracking :: Global < UrlExprConfig > ;
128132
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 > ;
130136
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"
132151 }
133152}
134153
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 )
137158select sink .getNode ( ) , encodedValue , sink , "This " + kind + " may include data from a $@." ,
138159 encodedValue .getNode ( ) , "possibly inappropriately encoded value"
0 commit comments