Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e091fde

Browse files
committed
JS: Port DomBasedXss
1 parent 2818fa6 commit e091fde

8 files changed

Lines changed: 1536 additions & 4019 deletions

File tree

javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssCustomizations.qll

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,30 @@ module DomBasedXss {
1818
/** A sanitizer for DOM-based XSS vulnerabilities. */
1919
abstract class Sanitizer extends Shared::Sanitizer { }
2020

21+
/**
22+
* A barrier guard for any tainted value.
23+
*/
24+
abstract class BarrierGuard extends DataFlow::Node {
25+
/**
26+
* Holds if this node acts as a barrier for data flow, blocking further flow from `e` if `this` evaluates to `outcome`.
27+
*/
28+
predicate blocksExpr(boolean outcome, Expr e) { none() }
29+
30+
/**
31+
* Holds if this node acts as a barrier for `label`, blocking further flow from `e` if `this` evaluates to `outcome`.
32+
*/
33+
predicate blocksExpr(boolean outcome, Expr e, DataFlow::FlowLabel label) { none() }
34+
}
35+
36+
/** A subclass of `BarrierGuard` that is used for backward compatibility with the old data flow library. */
37+
abstract class BarrierGuardLegacy extends BarrierGuard, TaintTracking::SanitizerGuardNode {
38+
override predicate sanitizes(boolean outcome, Expr e) { this.blocksExpr(outcome, e) }
39+
40+
override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) {
41+
this.blocksExpr(outcome, e, label)
42+
}
43+
}
44+
2145
/**
2246
* An expression whose value is interpreted as HTML
2347
* and may be inserted into the DOM through a library.
@@ -347,9 +371,8 @@ module DomBasedXss {
347371
/**
348372
* A sanitizer that blocks the `PrefixString` label when the start of the string is being tested as being of a particular prefix.
349373
*/
350-
abstract class PrefixStringSanitizer extends TaintTracking::LabeledSanitizerGuardNode instanceof StringOps::StartsWith
351-
{
352-
override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) {
374+
abstract class PrefixStringSanitizer extends BarrierGuardLegacy instanceof StringOps::StartsWith {
375+
override predicate blocksExpr(boolean outcome, Expr e, DataFlow::FlowLabel label) {
353376
e = super.getBaseString().asExpr() and
354377
label = prefixLabel() and
355378
outcome = super.getPolarity()

javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssQuery.qll

Lines changed: 68 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ class HtmlSink extends DataFlow::Node instanceof Sink {
2323
deprecated class HTMLSink = HtmlSink;
2424

2525
/**
26-
* A taint-tracking configuration for reasoning about XSS.
26+
* A taint-tracking configuration for reasoning about XSS by DOM manipulation.
27+
*
2728
* Both ordinary HTML sinks, URL sinks, and JQuery selector based sinks.
2829
* - HTML sinks are sinks for any tainted value
2930
* - URL sinks are only sinks when the scheme is user controlled
@@ -34,10 +35,10 @@ deprecated class HTMLSink = HtmlSink;
3435
* - Taint: a tainted value where the attacker controls part of the value.
3536
* - PrefixLabel: a tainted value where the attacker controls the prefix
3637
*/
37-
class Configuration extends TaintTracking::Configuration {
38-
Configuration() { this = "HtmlInjection" }
38+
module DomBasedXssConfig implements DataFlow::StateConfigSig {
39+
class FlowState = DataFlow::FlowLabel;
3940

40-
override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) {
41+
predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) {
4142
source instanceof Source and
4243
(label.isTaint() or label = prefixLabel()) and
4344
not source = TaintedUrlSuffix::source()
@@ -46,7 +47,7 @@ class Configuration extends TaintTracking::Configuration {
4647
label = TaintedUrlSuffix::label()
4748
}
4849

49-
override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) {
50+
predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) {
5051
sink instanceof HtmlSink and
5152
label = [TaintedUrlSuffix::label(), prefixLabel(), DataFlow::FlowLabel::taint()]
5253
or
@@ -57,23 +58,11 @@ class Configuration extends TaintTracking::Configuration {
5758
label = prefixLabel()
5859
}
5960

60-
override predicate isSanitizer(DataFlow::Node node) {
61-
super.isSanitizer(node)
62-
or
63-
node instanceof Sanitizer
64-
}
65-
66-
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) {
67-
guard instanceof PrefixStringSanitizerActivated or
68-
guard instanceof QuoteGuard or
69-
guard instanceof ContainsHtmlGuard
70-
}
61+
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
7162

72-
override predicate isLabeledBarrier(DataFlow::Node node, DataFlow::FlowLabel lbl) {
73-
super.isLabeledBarrier(node, lbl)
74-
or
75-
// copy all taint barriers to the TaintedUrlSuffix/PrefixLabel label. This copies both the ordinary sanitizers and the sanitizer-guards.
76-
super.isLabeledBarrier(node, DataFlow::FlowLabel::taint()) and
63+
predicate isBarrier(DataFlow::Node node, DataFlow::FlowLabel lbl) {
64+
// copy all taint barrier guards to the TaintedUrlSuffix/PrefixLabel label
65+
TaintTracking::defaultSanitizer(node) and
7766
lbl = [TaintedUrlSuffix::label(), prefixLabel()]
7867
or
7968
// any non-first string-concatenation leaf is a barrier for the prefix label.
@@ -89,55 +78,89 @@ class Configuration extends TaintTracking::Configuration {
8978
or
9079
isOptionallySanitizedNode(node) and
9180
lbl = [DataFlow::FlowLabel::taint(), prefixLabel(), TaintedUrlSuffix::label()]
81+
or
82+
node = DataFlow::MakeLabeledBarrierGuard<BarrierGuard>::getABarrierNode(lbl)
9283
}
9384

94-
override predicate isAdditionalFlowStep(
95-
DataFlow::Node src, DataFlow::Node trg, DataFlow::FlowLabel inlbl, DataFlow::FlowLabel outlbl
85+
predicate isAdditionalFlowStep(
86+
DataFlow::Node node1, DataFlow::FlowLabel state1, DataFlow::Node node2,
87+
DataFlow::FlowLabel state2
9688
) {
97-
TaintedUrlSuffix::step(src, trg, inlbl, outlbl)
89+
TaintedUrlSuffix::step(node1, node2, state1, state2)
9890
or
9991
exists(DataFlow::Node operator |
100-
StringConcatenation::taintStep(src, trg, operator, _) and
92+
StringConcatenation::taintStep(node1, node2, operator, _) and
10193
StringConcatenation::getOperand(operator, 0).getStringValue() = "<" + any(string s) and
102-
inlbl = TaintedUrlSuffix::label() and
103-
outlbl.isTaint()
94+
state1 = TaintedUrlSuffix::label() and
95+
state2.isTaint()
10496
)
10597
or
106-
// inherit all ordinary taint steps for prefixLabel
107-
inlbl = prefixLabel() and
108-
outlbl = prefixLabel() and
109-
TaintTracking::sharedTaintStep(src, trg)
110-
or
111-
// steps out of taintedSuffixlabel to taint-label are also a steps to prefixLabel.
112-
TaintedUrlSuffix::step(src, trg, TaintedUrlSuffix::label(), DataFlow::FlowLabel::taint()) and
113-
inlbl = TaintedUrlSuffix::label() and
114-
outlbl = prefixLabel()
98+
// steps out of taintedSuffixlabel to taint-label are also steps to prefixLabel.
99+
TaintedUrlSuffix::step(node1, node2, TaintedUrlSuffix::label(), DataFlow::FlowLabel::taint()) and
100+
state1 = TaintedUrlSuffix::label() and
101+
state2 = prefixLabel()
115102
or
103+
// FIXME: this fails to work in the test case at jquery.js:37
116104
exists(DataFlow::FunctionNode callback, DataFlow::Node arg |
117105
any(JQuery::MethodCall c).interpretsArgumentAsHtml(arg) and
118106
callback = arg.getABoundFunctionValue(_) and
119-
src = callback.getReturnNode() and
120-
trg = callback and
121-
inlbl = outlbl
107+
node1 = callback.getReturnNode() and
108+
node2 = callback and
109+
state1 = state2
122110
)
123111
}
124112
}
125113

126-
private class PrefixStringSanitizerActivated extends TaintTracking::SanitizerGuardNode,
127-
PrefixStringSanitizer
128-
{
114+
/**
115+
* Taint-tracking for reasoning about XSS by DOM manipulation.
116+
*/
117+
module DomBasedXssFlow = TaintTracking::GlobalWithState<DomBasedXssConfig>;
118+
119+
/**
120+
* DEPRECATED. Use the `DomBasedXssFlow` module instead.
121+
*/
122+
deprecated class Configuration extends TaintTracking::Configuration {
123+
Configuration() { this = "HtmlInjection" }
124+
125+
override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) {
126+
DomBasedXssConfig::isSource(source, label)
127+
}
128+
129+
override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) {
130+
DomBasedXssConfig::isSink(sink, label)
131+
}
132+
133+
override predicate isSanitizer(DataFlow::Node node) { DomBasedXssConfig::isBarrier(node) }
134+
135+
override predicate isLabeledBarrier(DataFlow::Node node, DataFlow::FlowLabel lbl) {
136+
DomBasedXssConfig::isBarrier(node, lbl)
137+
}
138+
139+
override predicate isAdditionalFlowStep(
140+
DataFlow::Node node1, DataFlow::Node node2, DataFlow::FlowLabel state1,
141+
DataFlow::FlowLabel state2
142+
) {
143+
DomBasedXssConfig::isAdditionalFlowStep(node1, state1, node2, state2)
144+
or
145+
// inherit all ordinary taint steps for the prefix label
146+
state1 = prefixLabel() and
147+
state2 = prefixLabel() and
148+
TaintTracking::sharedTaintStep(node1, node2)
149+
}
150+
}
151+
152+
private class PrefixStringSanitizerActivated extends PrefixStringSanitizer {
129153
PrefixStringSanitizerActivated() { this = this }
130154
}
131155

132156
private class PrefixStringActivated extends DataFlow::FlowLabel, PrefixString {
133157
PrefixStringActivated() { this = this }
134158
}
135159

136-
private class QuoteGuard extends TaintTracking::SanitizerGuardNode, Shared::QuoteGuard {
160+
private class QuoteGuard extends Shared::QuoteGuard {
137161
QuoteGuard() { this = this }
138162
}
139163

140-
private class ContainsHtmlGuard extends TaintTracking::SanitizerGuardNode, Shared::ContainsHtmlGuard
141-
{
164+
private class ContainsHtmlGuard extends Shared::ContainsHtmlGuard {
142165
ContainsHtmlGuard() { this = this }
143166
}

javascript/ql/src/Security/CWE-079/Xss.ql

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414

1515
import javascript
1616
import semmle.javascript.security.dataflow.DomBasedXssQuery
17-
import DataFlow::PathGraph
17+
import DataFlow::DeduplicatePathGraph<DomBasedXssFlow::PathNode, DomBasedXssFlow::PathGraph>
1818

19-
from DataFlow::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
20-
where cfg.hasFlowPath(source, sink)
19+
from PathNode source, PathNode sink
20+
where DomBasedXssFlow::flowPath(source.getAnOriginalPathNode(), sink.getAnOriginalPathNode())
2121
select sink.getNode(), source, sink,
2222
sink.getNode().(Sink).getVulnerabilityKind() + " vulnerability due to $@.", source.getNode(),
2323
"user-provided value"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
| query-tests/Security/CWE-079/DomBasedXss/sanitiser.js:25 | did not expect an alert, but found an alert for HtmlInjection | OK | ConsistencyConfig |
2+
| query-tests/Security/CWE-079/DomBasedXss/sanitiser.js:28 | did not expect an alert, but found an alert for HtmlInjection | OK | ConsistencyConfig |
3+
| query-tests/Security/CWE-079/DomBasedXss/sanitiser.js:35 | did not expect an alert, but found an alert for HtmlInjection | OK | ConsistencyConfig |
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
import javascript
22
import testUtilities.ConsistencyChecking
3-
import semmle.javascript.security.dataflow.DomBasedXssQuery as DomXss
3+
import semmle.javascript.security.dataflow.DomBasedXssQuery
4+
5+
class ConsistencyConfig extends ConsistencyConfiguration {
6+
ConsistencyConfig() { this = "ConsistencyConfig" }
7+
8+
override DataFlow::Node getAnAlert() { DomBasedXssFlow::flow(_, result) }
9+
}

0 commit comments

Comments
 (0)