11import 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/**
0 commit comments