forked from github/codeql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathXSS.qll
More file actions
130 lines (115 loc) · 4.5 KB
/
Copy pathXSS.qll
File metadata and controls
130 lines (115 loc) · 4.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/** Provides classes to reason about Cross-site scripting (XSS) vulnerabilities. */
import java
import semmle.code.java.frameworks.Servlets
import semmle.code.java.frameworks.android.WebView
import semmle.code.java.frameworks.spring.SpringController
import semmle.code.java.frameworks.spring.SpringHttp
import semmle.code.java.frameworks.javaee.jsf.JSFRenderer
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.TaintTracking2
private import semmle.code.java.dataflow.ExternalFlow
/** A sink that represent a method that outputs data without applying contextual output encoding. */
abstract class XssSink extends DataFlow::Node { }
/** A sanitizer that neutralizes dangerous characters that can be used to perform a XSS attack. */
abstract class XssSanitizer extends DataFlow::Node { }
/**
* A sink that represent a method that outputs data without applying contextual output encoding,
* and which should truncate flow paths such that downstream sinks are not flagged as well.
*/
abstract class XssSinkBarrier extends XssSink { }
/**
* A unit class for adding additional taint steps.
*
* Extend this class to add additional taint steps that should apply to the XSS
* taint configuration.
*/
class XssAdditionalTaintStep extends Unit {
/**
* Holds if the step from `node1` to `node2` should be considered a taint
* step for XSS taint configurations.
*/
abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);
}
/** A default sink representing methods susceptible to XSS attacks. */
private class DefaultXssSink extends XssSink {
DefaultXssSink() {
sinkNode(this, "xss")
or
exists(XssVulnerableWriterSourceToWritingMethodFlowConfig writer, MethodAccess ma |
ma.getMethod() instanceof WritingMethod and
writer.hasFlowToExpr(ma.getQualifier()) and
this.asExpr() = ma.getArgument(_)
)
}
}
/** A default sanitizer that considers numeric and boolean typed data safe for writing to output. */
private class DefaultXssSanitizer extends XssSanitizer {
DefaultXssSanitizer() {
this.getType() instanceof NumericType or
this.getType() instanceof BooleanType or
// Match `org.springframework.web.util.HtmlUtils.htmlEscape` and possibly other methods like it.
this.asExpr().(MethodAccess).getMethod().getName().regexpMatch("(?i)html_?escape.*")
}
}
/** A configuration that tracks data from a servlet writer to an output method. */
private class XssVulnerableWriterSourceToWritingMethodFlowConfig extends TaintTracking2::Configuration {
XssVulnerableWriterSourceToWritingMethodFlowConfig() {
this = "XSS::XssVulnerableWriterSourceToWritingMethodFlowConfig"
}
override predicate isSource(DataFlow::Node src) {
src.asExpr() instanceof XssVulnerableWriterSource
}
override predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma |
sink.asExpr() = ma.getQualifier() and ma.getMethod() instanceof WritingMethod
)
}
}
/** A method that can be used to output data to an output stream or writer. */
private class WritingMethod extends Method {
WritingMethod() {
this.getDeclaringType().getAnAncestor().hasQualifiedName("java.io", _) and
(
this.getName().matches("print%") or
this.getName() = "append" or
this.getName() = "format" or
this.getName() = "write"
)
}
}
/** An output stream or writer that writes to a servlet, JSP or JSF response. */
class XssVulnerableWriterSource extends MethodAccess {
XssVulnerableWriterSource() {
this.getMethod() instanceof ServletResponseGetWriterMethod
or
this.getMethod() instanceof ServletResponseGetOutputStreamMethod
or
exists(Method m | m = this.getMethod() |
m.getDeclaringType().getQualifiedName() = "javax.servlet.jsp.JspContext" and
m.getName() = "getOut"
)
or
this.getMethod() instanceof FacesGetResponseWriterMethod
or
this.getMethod() instanceof FacesGetResponseStreamMethod
}
}
/**
* DEPRECATED: Use `XssVulnerableWriterSource` instead.
*/
deprecated class ServletWriterSource = XssVulnerableWriterSource;
/**
* Holds if `s` is an HTTP Content-Type vulnerable to XSS.
*/
bindingset[s]
predicate isXssVulnerableContentType(string s) {
s.regexpMatch("(?i)text/(html|xml|xsl|rdf|vtt|cache-manifest).*") or
s.regexpMatch("(?i)application/(.*\\+)?xml.*") or
s.regexpMatch("(?i)cache-manifest.*") or
s.regexpMatch("(?i)image/svg\\+xml.*")
}
/**
* Holds if `s` is an HTTP Content-Type that is not vulnerable to XSS.
*/
bindingset[s]
predicate isXssSafeContentType(string s) { not isXssVulnerableContentType(s) }