Skip to content

Commit 347fd57

Browse files
committed
Refactor to avoid duplicated logic
1 parent b20b7c7 commit 347fd57

File tree

1 file changed

+48
-41
lines changed

1 file changed

+48
-41
lines changed

java/ql/lib/semmle/code/java/frameworks/spring/SpringWebClient.qll

Lines changed: 48 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -30,41 +30,60 @@ class SpringWebClient extends Interface {
3030

3131
private 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+
3366
private 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

Comments
 (0)