@@ -30,41 +30,60 @@ class SpringWebClient extends Interface {
3030
3131private import semmle.code.java.security.RequestForgery
3232
33+ /** The method `getForObject` on `org.springframework.web.reactive.function.client.RestTemplate`. */
34+ class SpringRestTemplateGetForObjectMethod extends Method {
35+ SpringRestTemplateGetForObjectMethod ( ) {
36+ this .getDeclaringType ( ) instanceof SpringRestTemplate and
37+ this .hasName ( "getForObject" )
38+ }
39+ }
40+
41+ /** A call to the method `getForObject` on `org.springframework.web.reactive.function.client.RestTemplate`. */
42+ class SpringRestTemplateGetForObjectMethodCall extends MethodCall {
43+ SpringRestTemplateGetForObjectMethodCall ( ) {
44+ this .getMethod ( ) instanceof SpringRestTemplateGetForObjectMethod
45+ }
46+
47+ /** Gets the first argument, if it is a compile time constant. */
48+ CompileTimeConstantExpr getConstantUrl ( ) { result = this .getArgument ( 0 ) }
49+
50+ /**
51+ * Holds if the first argument is a compile time constant and it has a
52+ * placeholder at offset `offset`, and there are `idx` placeholders that
53+ * appear before it.
54+ */
55+ predicate urlHasPlaceholderAtOffset ( int idx , int offset ) {
56+ exists (
57+ this .getConstantUrl ( )
58+ .getStringValue ( )
59+ .replaceAll ( "\\{" , " " )
60+ .replaceAll ( "\\}" , " " )
61+ .regexpFind ( "\\{[^}]*\\}" , idx , offset )
62+ )
63+ }
64+ }
65+
3366private class SpringWebClientRestTemplateGetForObject extends RequestForgerySink {
3467 SpringWebClientRestTemplateGetForObject ( ) {
35- exists ( Method m , MethodCall mc , int i |
36- m .getDeclaringType ( ) instanceof SpringRestTemplate and
37- m .hasName ( "getForObject" ) and
38- mc .getMethod ( ) = m and
39- // Note that mc.getArgument(0) is modeled separately. This model is for
40- // arguments beyond the first two. There are two relevant overloads, one
41- // with third parameter type `Object...` and one with third parameter
42- // type `Map<String, ?>`. For the latter we cannot deal with mapvalue
43- // content easily but there is a default implicit taint read at sinks
44- // that will catch it.
45- this .asExpr ( ) = mc .getArgument ( i + 2 ) and
46- i >= 0
68+ exists ( SpringRestTemplateGetForObjectMethodCall mc , int i |
69+ // Note that the first argument is modeled as a request forgery sink
70+ // separately. This model is for arguments beyond the first two. There
71+ // are two relevant overloads, one with third parameter type `Object...`
72+ // and one with third parameter type `Map<String, ?>`. For the latter we
73+ // cannot deal with MapValue content easily but there is a default
74+ // implicit taint read at sinks that will catch it.
75+ i >= 0 and
76+ this .asExpr ( ) = mc .getArgument ( i + 2 )
4777 |
4878 // If we can determine that part of mc.getArgument(0) is a hostname
4979 // sanitizing prefix, then we count how many placeholders occur before it
5080 // and only consider that many arguments beyond the first two as sinks.
5181 // For the `Map<String, ?>` overload this has the effect of only
5282 // considering the map values as sinks if there is at least one
5383 // placeholder in the URL before the hostname sanitizing prefix.
54- exists ( HostnameSanitizingPrefix hsp |
55- hsp = mc .getArgument ( 0 ) and
56- i <=
57- max ( int occurrenceIndex , int occurrenceOffset |
58- exists (
59- hsp .getStringValue ( )
60- .replaceAll ( "\\{" , " " )
61- .replaceAll ( "\\}" , " " )
62- .regexpFind ( "\\{[^}]*\\}" , occurrenceIndex , occurrenceOffset )
63- ) and
64- occurrenceOffset < hsp .getOffset ( )
65- |
66- occurrenceIndex
67- )
84+ exists ( int offset |
85+ mc .urlHasPlaceholderAtOffset ( i , offset ) and
86+ offset < mc .getConstantUrl ( ) .( HostnameSanitizingPrefix ) .getOffset ( )
6887 )
6988 or
7089 // If we cannot determine that part of mc.getArgument(0) is a hostname
@@ -74,24 +93,12 @@ private class SpringWebClientRestTemplateGetForObject extends RequestForgerySink
7493 // For the `Map<String, ?>` overload this has the effect of only
7594 // considering the map values as sinks if there is at least one
7695 // placeholder in the URL.
77- not mc .getArgument ( 0 ) instanceof HostnameSanitizingPrefix and
78- i <=
79- max ( int occurrenceIndex |
80- exists (
81- mc .getArgument ( 0 )
82- .( CompileTimeConstantExpr )
83- .getStringValue ( )
84- .replaceAll ( "\\{" , " " )
85- .replaceAll ( "\\}" , " " )
86- .regexpFind ( "\\{[^}]*\\}" , occurrenceIndex , _)
87- )
88- |
89- occurrenceIndex
90- )
96+ not mc .getConstantUrl ( ) instanceof HostnameSanitizingPrefix and
97+ mc .urlHasPlaceholderAtOffset ( i , _)
9198 or
9299 // If we cannot determine the string value of mc.getArgument(0), then we
93100 // conservatively consider all arguments as sinks.
94- not exists ( mc .getArgument ( 0 ) . ( CompileTimeConstantExpr ) .getStringValue ( ) )
101+ not exists ( mc .getConstantUrl ( ) .getStringValue ( ) )
95102 )
96103 }
97104}
0 commit comments