Skip to content

Java: Improve modelling of Spring requests, flow steps and XSS sinks #3653

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 38 commits into from
Jul 8, 2020
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
f5dc033
Java: Improve modelling of Spring request methods
lcartey May 15, 2020
4300bc8
Java: Update RemoteFlowSource to use improve Spring request parameter
lcartey May 15, 2020
6de2b93
Java: Add SpringWebRequest to RemoteTaintedMethod
lcartey May 15, 2020
7c4251d
Java: Add flow out of Map and List
lcartey May 15, 2020
bfcc06d
Java: Improve Spring controller modelling
lcartey May 17, 2020
fd2cd60
Java: Modelling of the Spring HTTP classes.
lcartey May 17, 2020
1d12340
Java: Model Spring @ResponseBody methods.
lcartey May 17, 2020
7d555a7
Java: Track flow through HttpEntity and ResponseEntity
lcartey May 17, 2020
c59042f
Java: Taint tracking through String.replace(all)?
lcartey May 17, 2020
8057dff
Java: Add Spring XSS sinks
lcartey May 17, 2020
f6a99cb
Java: Model produces parameter to RequestMapping attribute.
lcartey May 17, 2020
e2cec58
Java: XSS - ignore Spring sinks when content-type is safe.
lcartey May 17, 2020
f6b2acc
Java: Model ResponseEntity.BodyBuilder
lcartey May 17, 2020
0db7cea
Java: Model taint flow through ResponseEntity.
lcartey May 17, 2020
8bd5f74
Java: SpringController - handle non-string literal produces values.
lcartey May 17, 2020
8678d5f
Java: Model untrusted user data types
lcartey May 17, 2020
93c28d4
Java: Add taint step to flow through Spring tainted user data class
lcartey May 17, 2020
cd6339f
Java: Add Spring flow out of HttpEntity and HttpHeader
lcartey May 17, 2020
9625e82
Java: Model Spring WebClients/RestTemplates.
lcartey May 17, 2020
f2edc53
Java: Add Spring RestTemplate return values to untrusted data types
lcartey May 17, 2020
2978af3
Java: Add RestTemplate as flow source.
lcartey May 17, 2020
6de612a
Java: Split SpringWebRequestGetMethod into its own class.
aschackmull Jul 3, 2020
a41c2d8
Java: Make a few predicates private and autoformat SpringController.
aschackmull Jul 6, 2020
2ae15f9
Java: Remove list, map, and StringReplaceMethod flow steps.
aschackmull Jul 6, 2020
2ce0921
Java: Clean up SpringHttp.qll
aschackmull Jul 6, 2020
a80e663
Java: Minor typo fix and autoformat
aschackmull Jul 6, 2020
5d8f9a7
Java: Misc grammar fixes.
aschackmull Jul 6, 2020
e6658c5
Java: Cleanup TaintTrackingUtil.qll
aschackmull Jul 6, 2020
5e9e7fe
Java: Add some qldoc and minor formatting.
aschackmull Jul 6, 2020
b06d1c7
Java: More qldoc and some formatting.
aschackmull Jul 6, 2020
ae21de9
Java: Misc grammar and formatting.
aschackmull Jul 6, 2020
f98460c
Java: Use SpringHttpEntity class.
aschackmull Jul 6, 2020
3fef5ca
Merge pull request #1 from aschackmull/java/spring-3653
lcartey Jul 7, 2020
48e4759
Merge branch 'master' into java/spring-3653-2
aschackmull Jul 8, 2020
581d496
Java: Fix LdapInjection qltest
aschackmull Jul 8, 2020
a4fe4f4
Java: Fix JndiInjection qltest
aschackmull Jul 8, 2020
b88ebd6
Java: Fix OgnlInjection qltest
aschackmull Jul 8, 2020
443c13d
Merge pull request #2 from aschackmull/java/spring-3653-2
lcartey Jul 8, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions java/ql/src/semmle/code/java/dataflow/FlowSources.qll
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ import semmle.code.java.frameworks.android.XmlParsing
import semmle.code.java.frameworks.android.WebView
import semmle.code.java.frameworks.JaxWS
import semmle.code.java.frameworks.android.Intent
import semmle.code.java.frameworks.SpringWeb
import semmle.code.java.frameworks.spring.SpringWeb
import semmle.code.java.frameworks.spring.SpringController
import semmle.code.java.frameworks.spring.SpringWebClient
import semmle.code.java.frameworks.Guice
import semmle.code.java.frameworks.struts.StrutsActions
import semmle.code.java.frameworks.Thrift
Expand Down Expand Up @@ -118,7 +120,7 @@ private class SpringMultipartFileSource extends RemoteFlowSource {

private class SpringServletInputParameterSource extends RemoteFlowSource {
SpringServletInputParameterSource() {
this.asParameter().getAnAnnotation() instanceof SpringServletInputAnnotation
this.asParameter() = any(SpringRequestMappingParameter srmp | srmp.isTaintedInput())
}

override string getSourceType() { result = "Spring servlet input parameter" }
Expand Down Expand Up @@ -215,6 +217,19 @@ private class RemoteTaintedMethod extends Method {
this instanceof HttpServletRequestGetRequestURIMethod or
this instanceof HttpServletRequestGetRequestURLMethod or
this instanceof HttpServletRequestGetRemoteUserMethod or
exists(SpringWebRequest swr |
this = swr.getAMethod() |
this.hasName("getDescription") or
this.hasName("getHeader") or
this.hasName("getHeaderNames") or
this.hasName("getHeaderValues") or
this.hasName("getParameter") or
this.hasName("getParameterMap") or
this.hasName("getParameterNames") or
this.hasName("getParameterValues")
// TODO consider getRemoteUser
) or
this instanceof SpringRestTemplateResponseEntityMethod or
this instanceof ServletRequestGetBodyMethod or
this instanceof CookieGetValueMethod or
this instanceof CookieGetNameMethod or
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ private import semmle.code.java.security.Validation
private import semmle.code.java.frameworks.android.Intent
private import semmle.code.java.frameworks.Guice
private import semmle.code.java.frameworks.Protobuf
private import semmle.code.java.frameworks.spring.SpringController
private import semmle.code.java.frameworks.spring.SpringHttp
private import semmle.code.java.Maps
private import semmle.code.java.dataflow.internal.ContainerFlow
private import semmle.code.java.frameworks.jackson.JacksonSerializability
Expand Down Expand Up @@ -252,6 +254,22 @@ private predicate constructorStep(Expr tracked, ConstructorCall sink) {
or
// a custom InputStream that wraps a tainted data source is tainted
inputStreamWrapper(sink.getConstructor(), argi)
or
// A SpringHttpEntity is a wrapper around a body and some headers
// Track flow through iff body is a String
exists(SpringHttpEntity she |
sink.getConstructor() = she.getAConstructor() and
argi = 0 and
tracked.getType() instanceof TypeString
)
or
// A SpringRequestEntity is a wrapper around a body and some headers
// Track flow through iff body is a String
exists(SpringResponseEntity sre |
sink.getConstructor() = sre.getAConstructor() and
argi = 0 and
tracked.getType() instanceof TypeString
)
)
}

Expand Down Expand Up @@ -358,6 +376,36 @@ private predicate taintPreservingQualifierToMethod(Method m) {
m = any(GuiceProvider gp).getAnOverridingGetMethod()
or
m = any(ProtobufMessageLite p).getAGetterMethod()
or
m instanceof MapMethod and
(
m.getName().regexpMatch("get|entrySet|keySet|values")
)
or
m.getDeclaringType().getSourceDeclaration().getASourceSupertype*().hasQualifiedName("java.util", "List") and
(
m.getName().regexpMatch("get|toArray|subList|spliterator|set|iterator|listIterator") or
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aschackmull Wouldn't it be better to replace these regexMatch calls with something like :

m.hasName([ "get", "toArray", ...])

(m.getName().regexpMatch("remove") and not m.getReturnType() instanceof BooleanType)
)
or
m instanceof StringReplaceMethod
or
exists(SpringUntrustedDataType dt |
m.(GetterMethod) = dt.getAMethod()
)
or
exists(SpringHttpEntity sre |
m = sre.getAMethod() and
m.getName().regexpMatch("getBody|getHeaders")
)
or
exists(SpringHttpHeaders headers |
m = headers.getAMethod() |
m.getReturnType() instanceof TypeString
or
m.getReturnType().(RefType).getSourceDeclaration().getASourceSupertype*().hasQualifiedName("java.util", "List") and
m.getReturnType().(ParameterizedType).getTypeArgument(0) instanceof TypeString
)
}

private class StringReplaceMethod extends Method {
Expand Down Expand Up @@ -393,6 +441,22 @@ private predicate argToMethodStep(Expr tracked, MethodAccess sink) {
tracked = ma.getAnArgument() and
sink = ma
)
or
exists(Method springResponseEntityOfOk |
sink.getMethod() = springResponseEntityOfOk and
springResponseEntityOfOk.getDeclaringType() instanceof SpringResponseEntity and
springResponseEntityOfOk.getName().regexpMatch("ok|of") and
tracked = sink.getArgument(0) and
tracked.getType() instanceof TypeString
)
or
exists(Method springResponseEntityBody |
sink.getMethod() = springResponseEntityBody and
springResponseEntityBody.getDeclaringType() instanceof SpringResponseEntityBodyBuilder and
springResponseEntityBody.getName().regexpMatch("body") and
tracked = sink.getArgument(0) and
tracked.getType() instanceof TypeString
)
}

/**
Expand Down
20 changes: 2 additions & 18 deletions java/ql/src/semmle/code/java/frameworks/SpringWeb.qll
Original file line number Diff line number Diff line change
@@ -1,19 +1,3 @@
import java

/** A Spring framework annotation indicating remote user input from servlets. */
class SpringServletInputAnnotation extends Annotation {
SpringServletInputAnnotation() {
exists(AnnotationType a |
a = this.getType() and
a.getPackage().getName() = "org.springframework.web.bind.annotation"
|
a.hasName("MatrixVariable") or
a.hasName("RequestParam") or
a.hasName("RequestHeader") or
a.hasName("CookieValue") or
a.hasName("RequestPart") or
a.hasName("PathVariable") or
a.hasName("RequestBody")
)
}
}
import spring.SpringController
import spring.SpringWeb
Loading