@@ -30,41 +30,60 @@ class SpringWebClient extends Interface {
30
30
31
31
private import semmle.code.java.security.RequestForgery
32
32
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
+
33
66
private class SpringWebClientRestTemplateGetForObject extends RequestForgerySink {
34
67
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 )
47
77
|
48
78
// If we can determine that part of mc.getArgument(0) is a hostname
49
79
// sanitizing prefix, then we count how many placeholders occur before it
50
80
// and only consider that many arguments beyond the first two as sinks.
51
81
// For the `Map<String, ?>` overload this has the effect of only
52
82
// considering the map values as sinks if there is at least one
53
83
// 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 ( )
68
87
)
69
88
or
70
89
// If we cannot determine that part of mc.getArgument(0) is a hostname
@@ -74,24 +93,12 @@ private class SpringWebClientRestTemplateGetForObject extends RequestForgerySink
74
93
// For the `Map<String, ?>` overload this has the effect of only
75
94
// considering the map values as sinks if there is at least one
76
95
// 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 , _)
91
98
or
92
99
// If we cannot determine the string value of mc.getArgument(0), then we
93
100
// conservatively consider all arguments as sinks.
94
- not exists ( mc .getArgument ( 0 ) . ( CompileTimeConstantExpr ) .getStringValue ( ) )
101
+ not exists ( mc .getConstantUrl ( ) .getStringValue ( ) )
95
102
)
96
103
}
97
104
}
0 commit comments