Skip to content

Commit 3fef5ca

Browse files
authored
Merge pull request #1 from aschackmull/java/spring-3653
Java: Review changes for #3653
2 parents 2978af3 + f98460c commit 3fef5ca

File tree

8 files changed

+127
-99
lines changed

8 files changed

+127
-99
lines changed

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

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -217,18 +217,7 @@ private class RemoteTaintedMethod extends Method {
217217
this instanceof HttpServletRequestGetRequestURIMethod or
218218
this instanceof HttpServletRequestGetRequestURLMethod or
219219
this instanceof HttpServletRequestGetRemoteUserMethod or
220-
exists(SpringWebRequest swr |
221-
this = swr.getAMethod() |
222-
this.hasName("getDescription") or
223-
this.hasName("getHeader") or
224-
this.hasName("getHeaderNames") or
225-
this.hasName("getHeaderValues") or
226-
this.hasName("getParameter") or
227-
this.hasName("getParameterMap") or
228-
this.hasName("getParameterNames") or
229-
this.hasName("getParameterValues")
230-
// TODO consider getRemoteUser
231-
) or
220+
this instanceof SpringWebRequestGetMethod or
232221
this instanceof SpringRestTemplateResponseEntityMethod or
233222
this instanceof ServletRequestGetBodyMethod or
234223
this instanceof CookieGetValueMethod or
@@ -247,6 +236,22 @@ private class RemoteTaintedMethod extends Method {
247236
}
248237
}
249238

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+
250255
private class EnvTaintedMethod extends Method {
251256
EnvTaintedMethod() {
252257
this instanceof MethodSystemGetenv or

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

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -377,34 +377,19 @@ private predicate taintPreservingQualifierToMethod(Method m) {
377377
or
378378
m = any(ProtobufMessageLite p).getAGetterMethod()
379379
or
380-
m instanceof MapMethod and
381-
(
382-
m.getName().regexpMatch("get|entrySet|keySet|values")
383-
)
384-
or
385-
m.getDeclaringType().getSourceDeclaration().getASourceSupertype*().hasQualifiedName("java.util", "List") and
386-
(
387-
m.getName().regexpMatch("get|toArray|subList|spliterator|set|iterator|listIterator") or
388-
(m.getName().regexpMatch("remove") and not m.getReturnType() instanceof BooleanType)
389-
)
380+
m instanceof GetterMethod and m.getDeclaringType() instanceof SpringUntrustedDataType
390381
or
391-
m instanceof StringReplaceMethod
382+
m.getDeclaringType() instanceof SpringHttpEntity and
383+
m.getName().regexpMatch("getBody|getHeaders")
392384
or
393-
exists(SpringUntrustedDataType dt |
394-
m.(GetterMethod) = dt.getAMethod()
395-
)
396-
or
397-
exists(SpringHttpEntity sre |
398-
m = sre.getAMethod() and
399-
m.getName().regexpMatch("getBody|getHeaders")
400-
)
401-
or
402-
exists(SpringHttpHeaders headers |
403-
m = headers.getAMethod() |
385+
exists(SpringHttpHeaders headers | m = headers.getAMethod() |
404386
m.getReturnType() instanceof TypeString
405387
or
406-
m.getReturnType().(RefType).getSourceDeclaration().getASourceSupertype*().hasQualifiedName("java.util", "List") and
407-
m.getReturnType().(ParameterizedType).getTypeArgument(0) instanceof TypeString
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+
)
408393
)
409394
}
410395

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
import java
22
import spring.SpringController
3-
import spring.SpringWeb
3+
import spring.SpringWeb

java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,10 @@ class SpringControllerAnnotation extends AnnotationType {
1919
/**
2020
* An annotation type that identifies Spring rest controllers.
2121
*
22-
* Rest controllers are the same as controllers, but imply the @ResponseBody annotation.
22+
* Rest controllers are the same as controllers, but imply the `@ResponseBody` annotation.
2323
*/
2424
class SpringRestControllerAnnotation extends SpringControllerAnnotation {
25-
SpringRestControllerAnnotation() {
26-
hasName("RestController")
27-
}
25+
SpringRestControllerAnnotation() { hasName("RestController") }
2826
}
2927

3028
/**
@@ -80,7 +78,7 @@ class SpringInitBinderMethod extends SpringControllerMethod {
8078
}
8179

8280
/**
83-
* An `AnnotationType` which is used to indicate a `RequestMapping`.
81+
* An `AnnotationType` that is used to indicate a `RequestMapping`.
8482
*/
8583
class SpringRequestMappingAnnotationType extends AnnotationType {
8684
SpringRequestMappingAnnotationType() {
@@ -93,7 +91,7 @@ class SpringRequestMappingAnnotationType extends AnnotationType {
9391
}
9492

9593
/**
96-
* An `AnnotationType` which is used to indicate a `ResponseBody`.
94+
* An `AnnotationType` that is used to indicate a `ResponseBody`.
9795
*/
9896
class SpringResponseBodyAnnotationType extends AnnotationType {
9997
SpringResponseBodyAnnotationType() {
@@ -107,6 +105,7 @@ class SpringResponseBodyAnnotationType extends AnnotationType {
107105
*/
108106
class SpringRequestMappingMethod extends SpringControllerMethod {
109107
Annotation requestMappingAnnotation;
108+
110109
SpringRequestMappingMethod() {
111110
// Any method that declares the @RequestMapping annotation, or overrides a method that declares
112111
// the annotation. We have to do this explicit check because the @RequestMapping annotation is
@@ -119,21 +118,18 @@ class SpringRequestMappingMethod extends SpringControllerMethod {
119118
}
120119

121120
/** Gets a request mapping parameter. */
122-
SpringRequestMappingParameter getARequestParameter() {
123-
result = getAParameter()
124-
}
121+
SpringRequestMappingParameter getARequestParameter() { result = getAParameter() }
125122

126123
/** Gets the "produces" @RequestMapping annotation value, if present. */
127124
string getProduces() {
128-
result = requestMappingAnnotation.getValue("produces").(CompileTimeConstantExpr).getStringValue()
125+
result =
126+
requestMappingAnnotation.getValue("produces").(CompileTimeConstantExpr).getStringValue()
129127
}
130128

131-
/** Holds if this is considered an @ResponseBody method. */
129+
/** Holds if this is considered an `@ResponseBody` method. */
132130
predicate isResponseBody() {
133-
getAnAnnotation().getType() instanceof SpringResponseBodyAnnotationType
134-
or
135-
getDeclaringType().getAnAnnotation().getType() instanceof SpringResponseBodyAnnotationType
136-
or
131+
getAnAnnotation().getType() instanceof SpringResponseBodyAnnotationType or
132+
getDeclaringType().getAnAnnotation().getType() instanceof SpringResponseBodyAnnotationType or
137133
getDeclaringType() instanceof SpringRestController
138134
}
139135
}
@@ -156,12 +152,14 @@ class SpringServletInputAnnotation extends Annotation {
156152
}
157153
}
158154

155+
/** An annotation of the type `org.springframework.web.bind.annotation.ModelAttribute`. */
159156
class SpringModelAttributeAnnotation extends Annotation {
160157
SpringModelAttributeAnnotation() {
161158
getType().hasQualifiedName("org.springframework.web.bind.annotation", "ModelAttribute")
162159
}
163160
}
164161

162+
/** A parameter of a `SpringRequestMappingMethod`. */
165163
class SpringRequestMappingParameter extends Parameter {
166164
SpringRequestMappingParameter() { getCallable() instanceof SpringRequestMappingMethod }
167165

@@ -180,29 +178,47 @@ class SpringRequestMappingParameter extends Parameter {
180178
getType().(RefType).getAnAncestor().hasQualifiedName("java.time", "ZoneId") or
181179
getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "OutputStream") or
182180
getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "Writer") or
183-
getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.web.servlet.mvc.support", "RedirectAttributes") or
181+
getType()
182+
.(RefType)
183+
.getAnAncestor()
184+
.hasQualifiedName("org.springframework.web.servlet.mvc.support", "RedirectAttributes") or
184185
// Also covers BindingResult. Note, you can access the field value through this interface, which should be considered tainted
185186
getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.validation", "Errors") or
186-
getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.web.bind.support", "SessionStatus") or
187-
getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.web.util", "UriComponentsBuilder") or
188-
getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.data.domain", "Pageable") or
187+
getType()
188+
.(RefType)
189+
.getAnAncestor()
190+
.hasQualifiedName("org.springframework.web.bind.support", "SessionStatus") or
191+
getType()
192+
.(RefType)
193+
.getAnAncestor()
194+
.hasQualifiedName("org.springframework.web.util", "UriComponentsBuilder") or
195+
getType()
196+
.(RefType)
197+
.getAnAncestor()
198+
.hasQualifiedName("org.springframework.data.domain", "Pageable") or
189199
this instanceof SpringModel
190200
}
191201

192-
predicate isExplicitlyTaintedInput() {
202+
private predicate isExplicitlyTaintedInput() {
193203
// InputStream or Reader parameters allow access to the body of a request
194204
getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "InputStream") or
195205
getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "Reader") or
196206
// The SpringServletInputAnnotations allow access to the URI, request parameters, cookie values and the body of the request
197207
this.getAnAnnotation() instanceof SpringServletInputAnnotation or
198208
// HttpEntity is like @RequestBody, but with a wrapper including the headers
199209
// TODO model unwrapping aspects
200-
getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.http", "HttpEntity<T>") or
201-
this.getAnAnnotation().getType().hasQualifiedName("org.springframework.web.bind.annotation", "RequestAttribute") or
202-
this.getAnAnnotation().getType().hasQualifiedName("org.springframework.web.bind.annotation", "SessionAttribute")
210+
getType().(RefType).getASourceSupertype*() instanceof SpringHttpEntity or
211+
this
212+
.getAnAnnotation()
213+
.getType()
214+
.hasQualifiedName("org.springframework.web.bind.annotation", "RequestAttribute") or
215+
this
216+
.getAnAnnotation()
217+
.getType()
218+
.hasQualifiedName("org.springframework.web.bind.annotation", "SessionAttribute")
203219
}
204220

205-
predicate isImplicitRequestParam() {
221+
private predicate isImplicitRequestParam() {
206222
// Any parameter which is not explicitly handled, is consider to be an `@RequestParam`, if
207223
// it is a simple bean property
208224
not isNotDirectlyTaintedInput() and
@@ -213,23 +229,24 @@ class SpringRequestMappingParameter extends Parameter {
213229
)
214230
}
215231

216-
predicate isImplicitModelAttribute() {
232+
private predicate isImplicitModelAttribute() {
217233
// Any parameter which is not explicitly handled, is consider to be an `@ModelAttribute`, if
218234
// it is not an implicit request param
219235
not isNotDirectlyTaintedInput() and
220236
not isExplicitlyTaintedInput() and
221237
not isImplicitRequestParam()
222238
}
223239

224-
/** Holds if this is an explicit or implicit @ModelAttribute parameter */
240+
/** Holds if this is an explicit or implicit `@ModelAttribute` parameter. */
225241
predicate isModelAttribute() {
226242
isImplicitModelAttribute() or
227243
getAnAnnotation() instanceof SpringModelAttributeAnnotation
228244
}
229245

230-
/** Holds if the input is tainted */
246+
/** Holds if the input is tainted. */
231247
predicate isTaintedInput() {
232-
isExplicitlyTaintedInput() or
248+
isExplicitlyTaintedInput()
249+
or
233250
// Any parameter which is not explicitly identified, is consider to be an `@RequestParam`, if
234251
// it is a simple bean property) or a @ModelAttribute if not
235252
not isNotDirectlyTaintedInput()
@@ -305,18 +322,18 @@ private RefType stripType(Type t) {
305322
}
306323

307324
/**
308-
* A user data type which may be populated from a HTTP request.
325+
* A user data type that may be populated from an HTTP request.
309326
*
310-
* This includes types directly referred to as either @ModelAttribute or @RequestBody parameters,
311-
* or types which are referred to by those types.
327+
* This includes types directly referred to as either `@ModelAttribute` or `@RequestBody` parameters,
328+
* or types that are referred to by those types.
312329
*/
313330
class SpringUntrustedDataType extends RefType {
314331
SpringUntrustedDataType() {
315332
exists(SpringRequestMappingParameter p |
316333
p.isModelAttribute()
317334
or
318335
p.getAnAnnotation().(SpringServletInputAnnotation).getType().hasName("RequestBody")
319-
|
336+
|
320337
this.fromSource() and
321338
this = stripType(p.getType())
322339
)
Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,40 @@
1+
/**
2+
* Provides classes for working with Spring classes and interfaces from
3+
* `org.springframework.http`.
4+
*/
5+
16
import java
27

8+
/** The class `org.springframework.http.HttpEntity` or an instantiation of it. */
39
class SpringHttpEntity extends Class {
410
SpringHttpEntity() {
5-
getSourceDeclaration()
6-
.getErasure()
7-
.(RefType)
8-
.hasQualifiedName("org.springframework.http", "HttpEntity")
11+
this.getSourceDeclaration().hasQualifiedName("org.springframework.http", "HttpEntity")
912
}
1013
}
1114

15+
/** The class `org.springframework.http.RequestEntity` or an instantiation of it. */
1216
class SpringRequestEntity extends Class {
1317
SpringRequestEntity() {
14-
getSourceDeclaration()
15-
.getErasure()
16-
.(RefType)
17-
.hasQualifiedName("org.springframework.http", "RequestEntity")
18+
this.getSourceDeclaration().hasQualifiedName("org.springframework.http", "RequestEntity")
1819
}
1920
}
2021

22+
/** The class `org.springframework.http.ResponseEntity` or an instantiation of it. */
2123
class SpringResponseEntity extends Class {
2224
SpringResponseEntity() {
23-
getSourceDeclaration()
24-
.getErasure()
25-
.(RefType)
26-
.hasQualifiedName("org.springframework.http", "ResponseEntity")
25+
this.getSourceDeclaration().hasQualifiedName("org.springframework.http", "ResponseEntity")
2726
}
2827
}
2928

29+
/** The nested class `BodyBuilder` in `org.springframework.http.ResponseEntity`. */
3030
class SpringResponseEntityBodyBuilder extends Interface {
3131
SpringResponseEntityBodyBuilder() {
32-
getSourceDeclaration().getEnclosingType() = any(SpringResponseEntity sre) and
33-
hasName("BodyBuilder")
32+
this.getSourceDeclaration().getEnclosingType() instanceof SpringResponseEntity and
33+
this.hasName("BodyBuilder")
3434
}
3535
}
3636

37+
/** The class `org.springframework.http.HttpHeaders`. */
3738
class SpringHttpHeaders extends Class {
38-
SpringHttpHeaders() { hasQualifiedName("org.springframework.http", "HttpHeaders") }
39-
}
39+
SpringHttpHeaders() { this.hasQualifiedName("org.springframework.http", "HttpHeaders") }
40+
}
Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
1+
/**
2+
* Provides classes for working with Spring web requests.
3+
*/
4+
15
import java
26

37
/** An interface for web requests in the Spring framework. */
48
class SpringWebRequest extends Class {
59
SpringWebRequest() {
6-
hasQualifiedName("org.springframework.web.context.request", "WebRequest")
10+
this.hasQualifiedName("org.springframework.web.context.request", "WebRequest")
711
}
812
}
913

1014
/** An interface for web requests in the Spring framework. */
1115
class SpringNativeWebRequest extends Class {
1216
SpringNativeWebRequest() {
13-
hasQualifiedName("org.springframework.web.context.request", "NativeWebRequest")
17+
this.hasQualifiedName("org.springframework.web.context.request", "NativeWebRequest")
1418
}
15-
}
19+
}

0 commit comments

Comments
 (0)