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

Skip to content

Commit 12289d4

Browse files
committed
JS: Migrate DomBasedXssQuery to FlowState
1 parent 114d4a1 commit 12289d4

3 files changed

Lines changed: 58 additions & 43 deletions

File tree

javascript/ql/lib/semmle/javascript/security/CommonFlowState.qll

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ private import TaintedUrlSuffixCustomizations
88
private newtype TFlowState =
99
TTaint() or
1010
TTaintedUrlSuffix() or
11+
TTaintedPrefix()
1112

1213
/**
1314
* A flow state indicating which part of a value is tainted.
@@ -24,6 +25,11 @@ class FlowState extends TFlowState {
2425
*/
2526
predicate isTaintedUrlSuffix() { this = TTaintedUrlSuffix() }
2627

28+
/**
29+
* Holds if this represents a string whose prefix is known to be tainted.
30+
*/
31+
predicate isTaintedPrefix() { this = TTaintedPrefix() }
32+
2733
/** Gets a string representation of this flow state. */
2834
string toString() {
2935
this.isTaint() and result = "taint"
@@ -56,6 +62,11 @@ module FlowState {
5662
*/
5763
FlowState taintedUrlSuffix() { result.isTaintedUrlSuffix() }
5864

65+
/**
66+
* Gets the flow state representing a string whose prefix is known to be tainted.
67+
*/
68+
FlowState taintedPrefix() { result.isTaintedPrefix() }
69+
5970
/** DEPRECATED. Gets the flow state corresponding to `label`. */
6071
deprecated FlowState fromFlowLabel(DataFlow::FlowLabel label) { result.toFlowLabel() = label }
6172
}

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

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ private import semmle.javascript.dataflow.InferredTypes
88

99
module DomBasedXss {
1010
private import Xss::Shared as Shared
11+
import semmle.javascript.security.CommonFlowState
1112

1213
/** A data flow source for DOM-based XSS vulnerabilities. */
1314
abstract class Source extends Shared::Source { }
@@ -28,16 +29,16 @@ module DomBasedXss {
2829
predicate blocksExpr(boolean outcome, Expr e) { none() }
2930

3031
/**
31-
* Holds if this node acts as a barrier for `label`, blocking further flow from `e` if `this` evaluates to `outcome`.
32+
* Holds if this node acts as a barrier for `state`, blocking further flow from `e` if `this` evaluates to `outcome`.
3233
*/
33-
predicate blocksExpr(boolean outcome, Expr e, DataFlow::FlowLabel label) { none() }
34+
predicate blocksExpr(boolean outcome, Expr e, FlowState state) { none() }
3435

3536
/** DEPRECATED. Use `blocksExpr` instead. */
3637
deprecated predicate sanitizes(boolean outcome, Expr e) { this.blocksExpr(outcome, e) }
3738

3839
/** DEPRECATED. Use `blocksExpr` instead. */
3940
deprecated predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) {
40-
this.blocksExpr(outcome, e, label)
41+
this.blocksExpr(outcome, e, FlowState::fromFlowLabel(label))
4142
}
4243
}
4344

@@ -379,20 +380,20 @@ module DomBasedXss {
379380
/**
380381
* A flow-label representing tainted values where the prefix is attacker controlled.
381382
*/
382-
abstract class PrefixString extends DataFlow::FlowLabel {
383+
abstract deprecated class PrefixString extends DataFlow::FlowLabel {
383384
PrefixString() { this = "PrefixString" }
384385
}
385386

386387
/** Gets the flow-label representing tainted values where the prefix is attacker controlled. */
387-
PrefixString prefixLabel() { any() }
388+
deprecated PrefixString prefixLabel() { any() }
388389

389390
/**
390391
* A sanitizer that blocks the `PrefixString` label when the start of the string is being tested as being of a particular prefix.
391392
*/
392393
abstract class PrefixStringSanitizer extends BarrierGuard instanceof StringOps::StartsWith {
393-
override predicate blocksExpr(boolean outcome, Expr e, DataFlow::FlowLabel label) {
394+
override predicate blocksExpr(boolean outcome, Expr e, FlowState state) {
394395
e = super.getBaseString().asExpr() and
395-
label = prefixLabel() and
396+
state.isTaintedPrefix() and
396397
outcome = super.getPolarity()
397398
}
398399
}

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

Lines changed: 39 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -27,81 +27,83 @@ class HtmlSink extends DataFlow::Node instanceof Sink {
2727
* - URL sinks are only sinks when the scheme is user controlled
2828
* - JQuery selector sinks are sinks when the tainted value can start with `<`.
2929
*
30-
* The above is achieved using three flow labels:
30+
* The above is achieved using three flow states:
3131
* - TaintedUrlSuffix: a URL where the attacker only controls a suffix.
3232
* - Taint: a tainted value where the attacker controls part of the value.
3333
* - PrefixLabel: a tainted value where the attacker controls the prefix
3434
*/
3535
module DomBasedXssConfig implements DataFlow::StateConfigSig {
36-
class FlowState = DataFlow::FlowLabel;
36+
import semmle.javascript.security.CommonFlowState
3737

38-
predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) {
38+
predicate isSource(DataFlow::Node source, FlowState state) {
3939
source instanceof Source and
40-
(label.isTaint() or label = prefixLabel()) and
40+
(state.isTaint() or state.isTaintedPrefix()) and
4141
not source = TaintedUrlSuffix::source()
4242
or
4343
source = TaintedUrlSuffix::source() and
44-
label = TaintedUrlSuffix::label()
44+
state.isTaintedUrlSuffix()
4545
}
4646

47-
predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) {
47+
predicate isSink(DataFlow::Node sink, FlowState state) {
4848
sink instanceof HtmlSink and
49-
label = [TaintedUrlSuffix::label(), prefixLabel(), DataFlow::FlowLabel::taint()]
49+
(state.isTaint() or state.isTaintedPrefix() or state.isTaintedUrlSuffix())
5050
or
5151
sink instanceof JQueryHtmlOrSelectorSink and
52-
label = [DataFlow::FlowLabel::taint(), prefixLabel()]
52+
(state.isTaint() or state.isTaintedPrefix())
5353
or
5454
sink instanceof WriteUrlSink and
55-
label = prefixLabel()
55+
state.isTaintedPrefix()
5656
}
5757

5858
predicate isBarrier(DataFlow::Node node) {
59-
node instanceof Sanitizer or node = Shared::BarrierGuard::getABarrierNode()
59+
node instanceof Sanitizer
60+
or
61+
node = Shared::BarrierGuard::getABarrierNode()
62+
or
63+
isOptionallySanitizedNode(node)
6064
}
6165

62-
predicate isBarrier(DataFlow::Node node, DataFlow::FlowLabel lbl) {
63-
// copy all taint barrier guards to the TaintedUrlSuffix/PrefixLabel label
66+
predicate isBarrier(DataFlow::Node node, FlowState state) {
67+
// copy all taint barrier guards to the TaintedUrlSuffix/PrefixLabel state
6468
TaintTracking::defaultSanitizer(node) and
65-
lbl = [TaintedUrlSuffix::label(), prefixLabel()]
69+
(state.isTaintedUrlSuffix() or state.isTaintedPrefix())
6670
or
67-
// any non-first string-concatenation leaf is a barrier for the prefix label.
71+
// any non-first string-concatenation leaf is a barrier for the prefix state.
6872
exists(StringOps::ConcatenationRoot root |
6973
node = root.getALeaf() and
7074
not node = root.getFirstLeaf() and
71-
lbl = prefixLabel()
75+
state.isTaintedPrefix()
7276
)
7377
or
74-
// we assume that `.join()` calls have a prefix, and thus block the prefix label.
78+
// we assume that `.join()` calls have a prefix, and thus block the prefix state.
7579
node = any(DataFlow::MethodCallNode call | call.getMethodName() = "join") and
76-
lbl = prefixLabel()
80+
state.isTaintedPrefix()
7781
or
78-
isOptionallySanitizedNode(node) and
79-
lbl = [DataFlow::FlowLabel::taint(), prefixLabel(), TaintedUrlSuffix::label()]
82+
TaintedUrlSuffix::isStateBarrier(node, TaintedUrlSuffix::FlowState::taintedUrlSuffix()) and
83+
state.isTaintedUrlSuffix()
8084
or
81-
TaintedUrlSuffix::isBarrier(node, lbl)
82-
or
83-
node = DataFlow::MakeLabeledBarrierGuard<BarrierGuard>::getABarrierNode(lbl)
85+
node = DataFlow::MakeStateBarrierGuard<FlowState, BarrierGuard>::getABarrierNode(state)
8486
}
8587

86-
predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowLabel label) { isSource(node, label) }
88+
predicate isBarrierIn(DataFlow::Node node, FlowState state) { isSource(node, state) }
8789

8890
predicate isAdditionalFlowStep(
89-
DataFlow::Node node1, DataFlow::FlowLabel state1, DataFlow::Node node2,
90-
DataFlow::FlowLabel state2
91+
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
9192
) {
92-
TaintedUrlSuffix::step(node1, node2, state1, state2)
93+
TaintedUrlSuffix::isAdditionalFlowStep(node1, state1, node2, state2)
9394
or
9495
exists(DataFlow::Node operator |
9596
StringConcatenation::taintStep(node1, node2, operator, _) and
9697
StringConcatenation::getOperand(operator, 0).getStringValue() = "<" + any(string s) and
97-
state1 = TaintedUrlSuffix::label() and
98+
state1.isTaintedUrlSuffix() and
9899
state2.isTaint()
99100
)
100101
or
101-
// steps out of taintedSuffixlabel to taint-label are also steps to prefixLabel.
102-
TaintedUrlSuffix::step(node1, node2, TaintedUrlSuffix::label(), DataFlow::FlowLabel::taint()) and
103-
state1 = TaintedUrlSuffix::label() and
104-
state2 = prefixLabel()
102+
// steps out of tainted-url-suffix to taint are also steps to tainted-prefix.
103+
TaintedUrlSuffix::isAdditionalFlowStep(node1, FlowState::taintedUrlSuffix(), node2,
104+
FlowState::taint()) and
105+
state1.isTaintedUrlSuffix() and
106+
state2.isTaintedPrefix()
105107
or
106108
// FIXME: this fails to work in the test case at jquery.js:37
107109
exists(DataFlow::FunctionNode callback, DataFlow::Node arg |
@@ -126,24 +128,25 @@ deprecated class Configuration extends TaintTracking::Configuration {
126128
Configuration() { this = "HtmlInjection" }
127129

128130
override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) {
129-
DomBasedXssConfig::isSource(source, label)
131+
DomBasedXssConfig::isSource(source, FlowState::fromFlowLabel(label))
130132
}
131133

132134
override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) {
133-
DomBasedXssConfig::isSink(sink, label)
135+
DomBasedXssConfig::isSink(sink, FlowState::fromFlowLabel(label))
134136
}
135137

136138
override predicate isSanitizer(DataFlow::Node node) { DomBasedXssConfig::isBarrier(node) }
137139

138140
override predicate isLabeledBarrier(DataFlow::Node node, DataFlow::FlowLabel lbl) {
139-
DomBasedXssConfig::isBarrier(node, lbl)
141+
DomBasedXssConfig::isBarrier(node, FlowState::fromFlowLabel(lbl))
140142
}
141143

142144
override predicate isAdditionalFlowStep(
143145
DataFlow::Node node1, DataFlow::Node node2, DataFlow::FlowLabel state1,
144146
DataFlow::FlowLabel state2
145147
) {
146-
DomBasedXssConfig::isAdditionalFlowStep(node1, state1, node2, state2)
148+
DomBasedXssConfig::isAdditionalFlowStep(node1, FlowState::fromFlowLabel(state1), node2,
149+
FlowState::fromFlowLabel(state2))
147150
or
148151
// inherit all ordinary taint steps for the prefix label
149152
state1 = prefixLabel() and
@@ -156,7 +159,7 @@ private class PrefixStringSanitizerActivated extends PrefixStringSanitizer {
156159
PrefixStringSanitizerActivated() { this = this }
157160
}
158161

159-
private class PrefixStringActivated extends DataFlow::FlowLabel, PrefixString {
162+
deprecated private class PrefixStringActivated extends DataFlow::FlowLabel, PrefixString {
160163
PrefixStringActivated() { this = this }
161164
}
162165

0 commit comments

Comments
 (0)