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

Skip to content

Commit f5dc033

Browse files
committed
Java: Improve modelling of Spring request methods
- Recognise @<httpverb>Mapping as well as @RequestMapping. - Identify tainted/not tainted parameters of RequestMapping methods.
1 parent d80a033 commit f5dc033

3 files changed

Lines changed: 98 additions & 19 deletions

File tree

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

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

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import java
2+
import SpringWeb
23

34
/**
45
* An annotation type that identifies Spring components.
@@ -58,6 +59,19 @@ class SpringInitBinderMethod extends SpringControllerMethod {
5859
}
5960
}
6061

62+
/**
63+
* An `AnnotationType` which is used to indicate a `RequestMapping`.
64+
*/
65+
class SpringRequestMappingAnnotationType extends AnnotationType {
66+
SpringRequestMappingAnnotationType() {
67+
// `@RequestMapping` used directly as an annotation.
68+
hasQualifiedName("org.springframework.web.bind.annotation", "RequestMapping")
69+
or
70+
// `@RequestMapping` can be used as a meta-annotation on other annotation types, e.g. GetMapping, PostMapping etc.
71+
getAnAnnotation().getType() instanceof SpringRequestMappingAnnotationType
72+
}
73+
}
74+
6175
/**
6276
* A method on a Spring controller that is executed in response to a web request.
6377
*/
@@ -68,9 +82,75 @@ class SpringRequestMappingMethod extends SpringControllerMethod {
6882
// not declared with @Inherited.
6983
exists(Method superMethod |
7084
this.overrides*(superMethod) and
71-
superMethod.hasAnnotation("org.springframework.web.bind.annotation", "RequestMapping")
85+
superMethod.getAnAnnotation().getType() instanceof SpringRequestMappingAnnotationType
7286
)
7387
}
88+
89+
/** Gets a request mapping parameter. */
90+
SpringRequestMappingParameter getARequestParameter() {
91+
result = getAParameter()
92+
}
93+
}
94+
95+
/** A Spring framework annotation indicating remote user input from servlets. */
96+
class SpringServletInputAnnotation extends Annotation {
97+
SpringServletInputAnnotation() {
98+
exists(AnnotationType a |
99+
a = this.getType() and
100+
a.getPackage().getName() = "org.springframework.web.bind.annotation"
101+
|
102+
a.hasName("MatrixVariable") or
103+
a.hasName("RequestParam") or
104+
a.hasName("RequestHeader") or
105+
a.hasName("CookieValue") or
106+
a.hasName("RequestPart") or
107+
a.hasName("PathVariable") or
108+
a.hasName("RequestBody")
109+
)
110+
}
111+
}
112+
113+
class SpringRequestMappingParameter extends Parameter {
114+
SpringRequestMappingParameter() { getCallable() instanceof SpringRequestMappingMethod }
115+
116+
/** Holds if the parameter should not be consider a direct source of taint. */
117+
predicate isNotDirectlyTaintedInput() {
118+
getType().(RefType).getAnAncestor() instanceof SpringWebRequest or
119+
getType().(RefType).getAnAncestor() instanceof SpringNativeWebRequest or
120+
getType().(RefType).getAnAncestor().hasQualifiedName("javax.servlet", "ServletRequest") or
121+
getType().(RefType).getAnAncestor().hasQualifiedName("javax.servlet", "ServletResponse") or
122+
getType().(RefType).getAnAncestor().hasQualifiedName("javax.servlet.http", "HttpSession") or
123+
getType().(RefType).getAnAncestor().hasQualifiedName("javax.servlet.http", "PushBuilder") or
124+
getType().(RefType).getAnAncestor().hasQualifiedName("java.security", "Principal") or
125+
getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.http", "HttpMethod") or
126+
getType().(RefType).getAnAncestor().hasQualifiedName("java.util", "Locale") or
127+
getType().(RefType).getAnAncestor().hasQualifiedName("java.util", "TimeZone") or
128+
getType().(RefType).getAnAncestor().hasQualifiedName("java.time", "ZoneId") or
129+
getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "OutputStream") or
130+
getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "Writer") or
131+
getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.web.servlet.mvc.support", "RedirectAttributes") or
132+
// Also covers BindingResult. Note, you can access the field value through this interface, which should be considered tainted
133+
getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.validation", "Errors") or
134+
getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.web.bind.support", "SessionStatus") or
135+
getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.web.util", "UriComponentsBuilder") or
136+
this instanceof SpringModel
137+
}
138+
139+
predicate isTaintedInput() {
140+
// InputStream or Reader parameters allow access to the body of a request
141+
getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "InputStream") or
142+
getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "Reader") or
143+
// The SpringServletInputAnnotations allow access to the URI, request parameters, cookie values and the body of the request
144+
this.getAnAnnotation() instanceof SpringServletInputAnnotation or
145+
// HttpEntity is like @RequestBody, but with a wrapper including the headers
146+
// TODO model unwrapping aspects
147+
getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.http", "HttpEntity<T>") or
148+
this.getAnAnnotation().getType().hasQualifiedName("org.springframework.web.bind.annotation", "RequestAttribute") or
149+
this.getAnAnnotation().getType().hasQualifiedName("org.springframework.web.bind.annotation", "SessionAttribute") or
150+
// Any parameter which is not explicitly identified, is consider to be an `@RequestParam`, if
151+
// it is a simple bean property) or a @ModelAttribute if not
152+
not isNotDirectlyTaintedInput()
153+
}
74154
}
75155

76156
/**
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import java
2+
3+
/** An interface for web requests in the Spring framework. */
4+
class SpringWebRequest extends Class {
5+
SpringWebRequest() {
6+
hasQualifiedName("org.springframework.web.context.request", "WebRequest")
7+
}
8+
}
9+
10+
/** An interface for web requests in the Spring framework. */
11+
class SpringNativeWebRequest extends Class {
12+
SpringNativeWebRequest() {
13+
hasQualifiedName("org.springframework.web.context.request", "NativeWebRequest")
14+
}
15+
}

0 commit comments

Comments
 (0)