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

Skip to content

Commit 18c23ec

Browse files
author
Max Schaefer
committed
JavaScript: Introduce shared library for modelling XSS-relevant concepts.
As its first application, this library makes it possible for `StoredXss` to reuse the `Source` classes of `DomBasedXss` and `ReflectedXss` without having to pull in their libraries (which contain their `Configuration` classes, causing `StoredXss` to recompute all flow information for the other two queries).
1 parent 0558b58 commit 18c23ec

5 files changed

Lines changed: 228 additions & 620 deletions

File tree

javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll

Lines changed: 1 addition & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,9 @@
44
*/
55

66
import javascript
7-
import semmle.javascript.security.dataflow.RemoteFlowSources
8-
import semmle.javascript.frameworks.jQuery
97

108
module DomBasedXss {
11-
/**
12-
* A data flow source for XSS vulnerabilities.
13-
*/
14-
abstract class Source extends DataFlow::Node { }
15-
16-
/**
17-
* A data flow sink for XSS vulnerabilities.
18-
*/
19-
abstract class Sink extends DataFlow::Node {
20-
/**
21-
* Gets the kind of vulnerability to report in the alert message.
22-
*
23-
* Defaults to `Cross-site scripting`, but may be overriden for sinks
24-
* that do not allow script injection, but injection of other undesirable HTML elements.
25-
*/
26-
string getVulnerabilityKind() { result = "Cross-site scripting" }
27-
}
28-
29-
/**
30-
* A sanitizer for XSS vulnerabilities.
31-
*/
32-
abstract class Sanitizer extends DataFlow::Node { }
9+
import Xss::DomBasedXss
3310

3411
/**
3512
* A taint-tracking configuration for reasoning about XSS.
@@ -68,146 +45,4 @@ module DomBasedXss {
6845
class LocationSource extends Source, DataFlow::ValueNode {
6946
LocationSource() { isDocumentURL(astNode) }
7047
}
71-
72-
/**
73-
* An expression whose value is interpreted as HTML
74-
* and may be inserted into the DOM through a library.
75-
*/
76-
class LibrarySink extends Sink, DataFlow::ValueNode {
77-
LibrarySink() {
78-
// call to a jQuery method that interprets its argument as HTML
79-
exists(JQueryMethodCall call | call.interpretsArgumentAsHtml(astNode) |
80-
// either the argument is always interpreted as HTML
81-
not call.interpretsArgumentAsSelector(astNode)
82-
or
83-
// or it doesn't start with something other than `<`, and so at least
84-
// _may_ be interpreted as HTML
85-
not exists(DataFlow::Node prefix, string strval |
86-
isPrefixOfJQueryHtmlString(astNode, prefix) and
87-
strval = prefix.asExpr().getStringValue() and
88-
not strval.regexpMatch("\\s*<.*")
89-
) and
90-
not isDocumentURL(astNode)
91-
)
92-
or
93-
// call to an Angular method that interprets its argument as HTML
94-
any(AngularJS::AngularJSCall call).interpretsArgumentAsHtml(this.asExpr())
95-
or
96-
// call to a WinJS function that interprets its argument as HTML
97-
exists(DataFlow::MethodCallNode mcn, string m |
98-
m = "setInnerHTMLUnsafe" or m = "setOuterHTMLUnsafe"
99-
|
100-
mcn.getMethodName() = m and
101-
this = mcn.getArgument(1)
102-
)
103-
}
104-
}
105-
106-
/**
107-
* Holds if `prefix` is a prefix of `htmlString`, which may be intepreted as
108-
* HTML by a jQuery method.
109-
*/
110-
private predicate isPrefixOfJQueryHtmlString(Expr htmlString, DataFlow::Node prefix) {
111-
any(JQueryMethodCall call).interpretsArgumentAsHtml(htmlString) and
112-
prefix = htmlString.flow()
113-
or
114-
exists(DataFlow::Node pred | isPrefixOfJQueryHtmlString(htmlString, pred) |
115-
prefix = StringConcatenation::getFirstOperand(pred)
116-
or
117-
prefix = pred.getAPredecessor()
118-
)
119-
}
120-
121-
/**
122-
* An expression whose value is interpreted as HTML or CSS
123-
* and may be inserted into the DOM.
124-
*/
125-
class DomSink extends Sink {
126-
DomSink() {
127-
// Call to a DOM function that inserts its argument into the DOM
128-
any(DomMethodCallExpr call).interpretsArgumentsAsHTML(this.asExpr())
129-
or
130-
// Assignment to a dangerous DOM property
131-
exists(DomPropWriteNode pw |
132-
pw.interpretsValueAsHTML() and
133-
this = DataFlow::valueNode(pw.getRhs())
134-
)
135-
or
136-
// `html` or `source.html` properties of React Native `WebView`
137-
exists(ReactNative::WebViewElement webView, DataFlow::SourceNode source |
138-
source = webView or
139-
source = webView.getAPropertyWrite("source").getRhs().getALocalSource()
140-
|
141-
this = source.getAPropertyWrite("html").getRhs()
142-
)
143-
}
144-
}
145-
146-
/**
147-
* An expression whose value is interpreted as HTML by a DOMParser.
148-
*/
149-
class DomParserSink extends Sink {
150-
DomParserSink() {
151-
exists(DataFlow::GlobalVarRefNode domParser |
152-
domParser.getName() = "DOMParser" and
153-
this = domParser.getAnInstantiation().getAMethodCall("parseFromString").getArgument(0)
154-
)
155-
}
156-
}
157-
158-
/**
159-
* A React `dangerouslySetInnerHTML` attribute, viewed as an XSS sink.
160-
*
161-
* Any write to the `__html` property of an object assigned to this attribute
162-
* is considered an XSS sink.
163-
*/
164-
class DangerouslySetInnerHtmlSink extends Sink, DataFlow::ValueNode {
165-
DangerouslySetInnerHtmlSink() {
166-
exists(DataFlow::Node danger, DataFlow::SourceNode valueSrc |
167-
exists(JSXAttribute attr |
168-
attr.getName() = "dangerouslySetInnerHTML" and
169-
attr.getValue() = danger.asExpr()
170-
)
171-
or
172-
exists(ReactElementDefinition def, DataFlow::ObjectLiteralNode props |
173-
props.flowsTo(def.getProps()) and
174-
props.hasPropertyWrite("dangerouslySetInnerHTML", danger)
175-
)
176-
|
177-
valueSrc.flowsTo(danger) and
178-
valueSrc.hasPropertyWrite("__html", this)
179-
)
180-
}
181-
}
182-
183-
/**
184-
* The HTML body of an email, viewed as an XSS sink.
185-
*/
186-
class EmailHtmlBodySink extends Sink {
187-
EmailHtmlBodySink() { this = any(EmailSender sender).getHtmlBody() }
188-
189-
override string getVulnerabilityKind() { result = "HTML injection" }
190-
}
191-
192-
193-
/**
194-
* A write to the `template` option of a Vue instance, viewed as an XSS sink.
195-
*/
196-
class VueTemplateSink extends DomBasedXss::Sink {
197-
VueTemplateSink() { this = any(Vue::Instance i).getTemplate() }
198-
}
199-
200-
/**
201-
* The tag name argument to the `createElement` parameter of the
202-
* `render` method of a Vue instance, viewed as an XSS sink.
203-
*/
204-
class VueCreateElementSink extends DomBasedXss::Sink {
205-
VueCreateElementSink() {
206-
exists(Vue::Instance i, DataFlow::FunctionNode f |
207-
f.flowsTo(i.getRender()) and
208-
this = f.getParameter(0).getACall().getArgument(0)
209-
)
210-
}
211-
}
212-
21348
}

javascript/ql/src/semmle/javascript/security/dataflow/ReflectedXss.qll

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,9 @@
44
*/
55

66
import javascript
7-
import semmle.javascript.security.dataflow.RemoteFlowSources
8-
import semmle.javascript.frameworks.jQuery
97

108
module ReflectedXss {
11-
/**
12-
* A data flow source for XSS vulnerabilities.
13-
*/
14-
abstract class Source extends DataFlow::Node { }
15-
16-
/**
17-
* A data flow sink for XSS vulnerabilities.
18-
*/
19-
abstract class Sink extends DataFlow::Node { }
20-
21-
/**
22-
* A sanitizer for XSS vulnerabilities.
23-
*/
24-
abstract class Sanitizer extends DataFlow::Node { }
9+
import Xss::ReflectedXss
2510

2611
/**
2712
* A taint-tracking configuration for reasoning about XSS.
@@ -47,23 +32,4 @@ module ReflectedXss {
4732
this.(HTTP::RequestHeaderAccess).getAHeaderName() = "referer"
4833
}
4934
}
50-
51-
/**
52-
* An expression that is sent as part of an HTTP response, considered as an XSS sink.
53-
*
54-
* We exclude cases where the route handler sets either an unknown content type or
55-
* a content type that does not (case-insensitively) contain the string "html". This
56-
* is to prevent us from flagging plain-text or JSON responses as vulnerable.
57-
*/
58-
private class HttpResponseSink extends Sink {
59-
HttpResponseSink() {
60-
exists(HTTP::ResponseSendArgument sendarg | sendarg = asExpr() |
61-
forall(HTTP::HeaderDefinition hd |
62-
hd = sendarg.getRouteHandler().getAResponseHeader("content-type")
63-
|
64-
exists(string tp | hd.defines("content-type", tp) | tp.toLowerCase().matches("%html%"))
65-
)
66-
)
67-
}
68-
}
6935
}

javascript/ql/src/semmle/javascript/security/dataflow/StoredXss.qll

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,9 @@
44
*/
55

66
import javascript
7-
import semmle.javascript.security.dataflow.RemoteFlowSources
8-
import semmle.javascript.security.dataflow.ReflectedXss as ReflectedXss
9-
import semmle.javascript.security.dataflow.DomBasedXss as DomBasedXss
107

118
module StoredXss {
12-
/**
13-
* A data flow source for XSS vulnerabilities.
14-
*/
15-
abstract class Source extends DataFlow::Node { }
16-
17-
/**
18-
* A data flow sink for XSS vulnerabilities.
19-
*/
20-
abstract class Sink extends DataFlow::Node { }
21-
22-
/**
23-
* A sanitizer for XSS vulnerabilities.
24-
*/
25-
abstract class Sanitizer extends DataFlow::Node { }
9+
import Xss::StoredXss
2610

2711
/**
2812
* A taint-tracking configuration for reasoning about XSS.
@@ -44,12 +28,4 @@ module StoredXss {
4428
class FileNameSourceAsSource extends Source {
4529
FileNameSourceAsSource() { this instanceof FileNameSource }
4630
}
47-
48-
/** An ordinary XSS sink, considered as a flow sink for stored XSS. */
49-
class XssSinkAsSink extends Sink {
50-
XssSinkAsSink() {
51-
this instanceof ReflectedXss::ReflectedXss::Sink or
52-
this instanceof DomBasedXss::DomBasedXss::Sink
53-
}
54-
}
5531
}

0 commit comments

Comments
 (0)