@@ -20,57 +20,47 @@ 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
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`. */
7157class 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
8878module 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 )
137159select sink .getNode ( ) , encodedValue , sink , "This " + kind + " may include data from a $@." ,
138160 encodedValue .getNode ( ) , "possibly inappropriately encoded value"
0 commit comments