@@ -7,65 +7,61 @@ import javascript
77private import semmle.javascript.security.TaintedUrlSuffix
88import DomBasedXssCustomizations:: DomBasedXss
99
10- /**
11- * DEPRECATED. Use `HtmlInjectionConfiguration` or `JQueryHtmlOrSelectorInjectionConfiguration`.
12- */
13- deprecated class Configuration = HtmlInjectionConfiguration ;
14-
1510/**
1611 * DEPRECATED. Use `Vue::VHtmlSourceWrite` instead.
1712 */
1813deprecated class VHtmlSourceWrite = Vue:: VHtmlSourceWrite ;
1914
20- /**
21- * A taint-tracking configuration for reasoning about XSS.
22- */
23- class HtmlInjectionConfiguration extends TaintTracking:: Configuration {
24- HtmlInjectionConfiguration ( ) { this = "HtmlInjection" }
25-
26- override predicate isSource ( DataFlow:: Node source ) { source instanceof Source }
27-
28- override predicate isSink ( DataFlow:: Node sink ) {
29- sink instanceof Sink and
30- not sink instanceof JQueryHtmlOrSelectorSink // Handled by JQueryHtmlOrSelectorInjectionConfiguration below
31- }
32-
33- override predicate isSanitizer ( DataFlow:: Node node ) {
34- super .isSanitizer ( node )
35- or
36- node instanceof Sanitizer
37- }
15+ /** DEPRECATED. Use `Configuration`. */
16+ deprecated class HtmlInjectionConfiguration = Configuration ;
3817
39- override predicate isSanitizerGuard ( TaintTracking:: SanitizerGuardNode guard ) {
40- guard instanceof SanitizerGuard
41- }
18+ /** DEPRECATED. Use `Configuration`. */
19+ deprecated class JQueryHtmlOrSelectorInjectionConfiguration = Configuration ;
4220
43- override predicate isSanitizerEdge ( DataFlow:: Node pred , DataFlow:: Node succ ) {
44- isOptionallySanitizedEdge ( pred , succ )
21+ /**
22+ * A sink that is not a URL write or a JQuery selector,
23+ * assumed to be a value that is interpreted as HTML.
24+ */
25+ class HTMLSink extends DataFlow:: Node instanceof Sink {
26+ HTMLSink ( ) {
27+ not this instanceof WriteURLSink and
28+ not this instanceof JQueryHtmlOrSelectorSink
4529 }
4630}
4731
4832/**
49- * A taint-tracking configuration for reasoning about injection into the jQuery `$` function
50- * or similar, where the interpretation of the input string depends on its first character.
33+ * A taint-tracking configuration for reasoning about XSS.
34+ * Both ordinary HTML sinks, URL sinks, and JQuery selector based sinks.
35+ * - HTML sinks are sinks for any tainted value
36+ * - URL sinks are only sinks when the scheme is user controlled
37+ * - JQuery selector sinks are sinks when the tainted value can start with `<`.
5138 *
52- * Values are only considered tainted if they can start with the `<` character.
39+ * The above is achieved using three flow labels:
40+ * - TaintedUrlSuffix: a URL where the attacker only controls a suffix.
41+ * - Taint: a tainted value where the attacker controls part of the value.
42+ * - PrefixLabel: a tainted value where the attacker controls the prefix
5343 */
54- class JQueryHtmlOrSelectorInjectionConfiguration extends TaintTracking:: Configuration {
55- JQueryHtmlOrSelectorInjectionConfiguration ( ) { this = "JQueryHtmlOrSelectorInjection " }
44+ class Configuration extends TaintTracking:: Configuration {
45+ Configuration ( ) { this = "HtmlInjection " }
5646
5747 override predicate isSource ( DataFlow:: Node source , DataFlow:: FlowLabel label ) {
58- // Reuse any source not derived from location
5948 source instanceof Source and
60- not source = [ DOM :: locationRef ( ) , DOM :: locationRef ( ) . getAPropertyRead ( ) ] and
61- label . isTaint ( )
49+ ( label . isTaint ( ) or label = prefixLabel ( ) ) and
50+ not source = TaintedUrlSuffix :: source ( )
6251 or
63- source = [ DOM :: locationSource ( ) , DOM :: locationRef ( ) . getAPropertyRead ( [ "hash" , "search" ] ) ] and
52+ source = TaintedUrlSuffix :: source ( ) and
6453 label = TaintedUrlSuffix:: label ( )
6554 }
6655
6756 override predicate isSink ( DataFlow:: Node sink , DataFlow:: FlowLabel label ) {
68- sink instanceof JQueryHtmlOrSelectorSink and label .isTaint ( )
57+ sink instanceof HTMLSink and
58+ label = [ TaintedUrlSuffix:: label ( ) , prefixLabel ( ) , DataFlow:: FlowLabel:: taint ( ) ]
59+ or
60+ sink instanceof JQueryHtmlOrSelectorSink and
61+ label = [ DataFlow:: FlowLabel:: taint ( ) , prefixLabel ( ) ]
62+ or
63+ sink instanceof WriteURLSink and
64+ label = prefixLabel ( )
6965 }
7066
7167 override predicate isSanitizer ( DataFlow:: Node node ) {
@@ -78,6 +74,32 @@ class JQueryHtmlOrSelectorInjectionConfiguration extends TaintTracking::Configur
7874 guard instanceof SanitizerGuard
7975 }
8076
77+ override predicate isLabeledBarrier ( DataFlow:: Node node , DataFlow:: FlowLabel lbl ) {
78+ super .isLabeledBarrier ( node , lbl )
79+ or
80+ // copy all taint barriers to the TaintedUrlSuffix/PrefixLabel label. This copies both the ordinary sanitizers and the sanitizer-guards.
81+ super .isLabeledBarrier ( node , DataFlow:: FlowLabel:: taint ( ) ) and
82+ lbl = [ TaintedUrlSuffix:: label ( ) , prefixLabel ( ) ]
83+ or
84+ // any non-first string-concatenation leaf is a barrier for the prefix label.
85+ exists ( StringOps:: ConcatenationRoot root |
86+ node = root .getALeaf ( ) and
87+ not node = root .getFirstLeaf ( ) and
88+ lbl = prefixLabel ( )
89+ )
90+ or
91+ // we assume that `.join()` calls have a prefix, and thus block the prefix label.
92+ node = any ( DataFlow:: MethodCallNode call | call .getMethodName ( ) = "join" ) and
93+ lbl = prefixLabel ( )
94+ }
95+
96+ override predicate isSanitizerEdge (
97+ DataFlow:: Node pred , DataFlow:: Node succ , DataFlow:: FlowLabel label
98+ ) {
99+ isOptionallySanitizedEdge ( pred , succ ) and
100+ label = [ DataFlow:: FlowLabel:: taint ( ) , prefixLabel ( ) , TaintedUrlSuffix:: label ( ) ]
101+ }
102+
81103 override predicate isAdditionalFlowStep (
82104 DataFlow:: Node src , DataFlow:: Node trg , DataFlow:: FlowLabel inlbl , DataFlow:: FlowLabel outlbl
83105 ) {
@@ -89,5 +111,26 @@ class JQueryHtmlOrSelectorInjectionConfiguration extends TaintTracking::Configur
89111 inlbl = TaintedUrlSuffix:: label ( ) and
90112 outlbl .isTaint ( )
91113 )
114+ or
115+ // inherit all ordinary taint steps for prefixLabel
116+ inlbl = prefixLabel ( ) and
117+ outlbl = prefixLabel ( ) and
118+ TaintTracking:: sharedTaintStep ( src , trg )
119+ or
120+ // steps out of taintedSuffixlabel to taint-label are also a steps to prefixLabel.
121+ TaintedUrlSuffix:: step ( src , trg , TaintedUrlSuffix:: label ( ) , DataFlow:: FlowLabel:: taint ( ) ) and
122+ inlbl = TaintedUrlSuffix:: label ( ) and
123+ outlbl = prefixLabel ( )
124+ }
125+ }
126+
127+ /**
128+ * A sanitizer that blocks the `PrefixString` label when the start of the string is being tested as being of a particular prefix.
129+ */
130+ class PrefixStringSanitizer extends SanitizerGuard , TaintTracking:: LabeledSanitizerGuardNode instanceof StringOps:: StartsWith {
131+ override predicate sanitizes ( boolean outcome , Expr e , DataFlow:: FlowLabel label ) {
132+ e = super .getBaseString ( ) .asExpr ( ) and
133+ label = prefixLabel ( ) and
134+ outcome = super .getPolarity ( )
92135 }
93136}
0 commit comments