Skip to content

Commit 528f250

Browse files
authored
Merge pull request #3653 from lcartey/java/improve-spring-support
Java: Improve modelling of Spring requests, flow steps and XSS sinks
2 parents 6ef7288 + 443c13d commit 528f250

File tree

18 files changed

+983
-466
lines changed

18 files changed

+983
-466
lines changed

java/ql/src/semmle/code/java/dataflow/FlowSources.qll

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ import semmle.code.java.frameworks.android.XmlParsing
1616
import semmle.code.java.frameworks.android.WebView
1717
import semmle.code.java.frameworks.JaxWS
1818
import semmle.code.java.frameworks.android.Intent
19-
import semmle.code.java.frameworks.SpringWeb
19+
import semmle.code.java.frameworks.spring.SpringWeb
20+
import semmle.code.java.frameworks.spring.SpringController
21+
import semmle.code.java.frameworks.spring.SpringWebClient
2022
import semmle.code.java.frameworks.Guice
2123
import semmle.code.java.frameworks.struts.StrutsActions
2224
import semmle.code.java.frameworks.Thrift
@@ -118,7 +120,7 @@ private class SpringMultipartFileSource extends RemoteFlowSource {
118120

119121
private class SpringServletInputParameterSource extends RemoteFlowSource {
120122
SpringServletInputParameterSource() {
121-
this.asParameter().getAnAnnotation() instanceof SpringServletInputAnnotation
123+
this.asParameter() = any(SpringRequestMappingParameter srmp | srmp.isTaintedInput())
122124
}
123125

124126
override string getSourceType() { result = "Spring servlet input parameter" }
@@ -215,6 +217,8 @@ private class RemoteTaintedMethod extends Method {
215217
this instanceof HttpServletRequestGetRequestURIMethod or
216218
this instanceof HttpServletRequestGetRequestURLMethod or
217219
this instanceof HttpServletRequestGetRemoteUserMethod or
220+
this instanceof SpringWebRequestGetMethod or
221+
this instanceof SpringRestTemplateResponseEntityMethod or
218222
this instanceof ServletRequestGetBodyMethod or
219223
this instanceof CookieGetValueMethod or
220224
this instanceof CookieGetNameMethod or
@@ -232,6 +236,22 @@ private class RemoteTaintedMethod extends Method {
232236
}
233237
}
234238

239+
private class SpringWebRequestGetMethod extends Method {
240+
SpringWebRequestGetMethod() {
241+
exists(SpringWebRequest swr | this = swr.getAMethod() |
242+
this.hasName("getDescription") or
243+
this.hasName("getHeader") or
244+
this.hasName("getHeaderNames") or
245+
this.hasName("getHeaderValues") or
246+
this.hasName("getParameter") or
247+
this.hasName("getParameterMap") or
248+
this.hasName("getParameterNames") or
249+
this.hasName("getParameterValues")
250+
// TODO consider getRemoteUser
251+
)
252+
}
253+
}
254+
235255
private class EnvTaintedMethod extends Method {
236256
EnvTaintedMethod() {
237257
this instanceof MethodSystemGetenv or

java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ private import semmle.code.java.security.Validation
88
private import semmle.code.java.frameworks.android.Intent
99
private import semmle.code.java.frameworks.Guice
1010
private import semmle.code.java.frameworks.Protobuf
11+
private import semmle.code.java.frameworks.spring.SpringController
12+
private import semmle.code.java.frameworks.spring.SpringHttp
1113
private import semmle.code.java.Maps
1214
private import semmle.code.java.dataflow.internal.ContainerFlow
1315
private import semmle.code.java.frameworks.jackson.JacksonSerializability
@@ -252,6 +254,22 @@ private predicate constructorStep(Expr tracked, ConstructorCall sink) {
252254
or
253255
// a custom InputStream that wraps a tainted data source is tainted
254256
inputStreamWrapper(sink.getConstructor(), argi)
257+
or
258+
// A SpringHttpEntity is a wrapper around a body and some headers
259+
// Track flow through iff body is a String
260+
exists(SpringHttpEntity she |
261+
sink.getConstructor() = she.getAConstructor() and
262+
argi = 0 and
263+
tracked.getType() instanceof TypeString
264+
)
265+
or
266+
// A SpringRequestEntity is a wrapper around a body and some headers
267+
// Track flow through iff body is a String
268+
exists(SpringResponseEntity sre |
269+
sink.getConstructor() = sre.getAConstructor() and
270+
argi = 0 and
271+
tracked.getType() instanceof TypeString
272+
)
255273
)
256274
}
257275

@@ -358,6 +376,21 @@ private predicate taintPreservingQualifierToMethod(Method m) {
358376
m = any(GuiceProvider gp).getAnOverridingGetMethod()
359377
or
360378
m = any(ProtobufMessageLite p).getAGetterMethod()
379+
or
380+
m instanceof GetterMethod and m.getDeclaringType() instanceof SpringUntrustedDataType
381+
or
382+
m.getDeclaringType() instanceof SpringHttpEntity and
383+
m.getName().regexpMatch("getBody|getHeaders")
384+
or
385+
exists(SpringHttpHeaders headers | m = headers.getAMethod() |
386+
m.getReturnType() instanceof TypeString
387+
or
388+
exists(ParameterizedType stringlist |
389+
m.getReturnType().(RefType).getASupertype*() = stringlist and
390+
stringlist.getSourceDeclaration().hasQualifiedName("java.util", "List") and
391+
stringlist.getTypeArgument(0) instanceof TypeString
392+
)
393+
)
361394
}
362395

363396
private class StringReplaceMethod extends Method {
@@ -393,6 +426,22 @@ private predicate argToMethodStep(Expr tracked, MethodAccess sink) {
393426
tracked = ma.getAnArgument() and
394427
sink = ma
395428
)
429+
or
430+
exists(Method springResponseEntityOfOk |
431+
sink.getMethod() = springResponseEntityOfOk and
432+
springResponseEntityOfOk.getDeclaringType() instanceof SpringResponseEntity and
433+
springResponseEntityOfOk.getName().regexpMatch("ok|of") and
434+
tracked = sink.getArgument(0) and
435+
tracked.getType() instanceof TypeString
436+
)
437+
or
438+
exists(Method springResponseEntityBody |
439+
sink.getMethod() = springResponseEntityBody and
440+
springResponseEntityBody.getDeclaringType() instanceof SpringResponseEntityBodyBuilder and
441+
springResponseEntityBody.getName().regexpMatch("body") and
442+
tracked = sink.getArgument(0) and
443+
tracked.getType() instanceof TypeString
444+
)
396445
}
397446

398447
/**
Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,3 @@
11
import java
2-
3-
/** A Spring framework annotation indicating remote user input from servlets. */
4-
class SpringServletInputAnnotation extends Annotation {
5-
SpringServletInputAnnotation() {
6-
exists(AnnotationType a |
7-
a = this.getType() and
8-
a.getPackage().getName() = "org.springframework.web.bind.annotation"
9-
|
10-
a.hasName("MatrixVariable") or
11-
a.hasName("RequestParam") or
12-
a.hasName("RequestHeader") or
13-
a.hasName("CookieValue") or
14-
a.hasName("RequestPart") or
15-
a.hasName("PathVariable") or
16-
a.hasName("RequestBody")
17-
)
18-
}
19-
}
2+
import spring.SpringController
3+
import spring.SpringWeb

0 commit comments

Comments
 (0)