23
23
@ Controller
24
24
public class UrlForwardTest extends HttpServlet implements Filter {
25
25
26
- // Spring-related test cases
26
+ // Spring `ModelAndView` test cases
27
27
@ GetMapping ("/bad1" )
28
28
public ModelAndView bad1 (String url ) {
29
29
return new ModelAndView (url ); // $ hasUrlForward
@@ -36,6 +36,7 @@ public ModelAndView bad2(String url) {
36
36
return modelAndView ;
37
37
}
38
38
39
+ // Spring `"forward:"` prefix test cases
39
40
@ GetMapping ("/bad3" )
40
41
public String bad3 (String url ) {
41
42
return "forward:" + url + "/swagger-ui/index.html" ; // $ hasUrlForward
@@ -47,6 +48,7 @@ public ModelAndView bad4(String url) {
47
48
return modelAndView ;
48
49
}
49
50
51
+ // `RequestDispatcher` test cases from a Spring `GetMapping` entry point
50
52
@ GetMapping ("/bad5" )
51
53
public void bad5 (String url , HttpServletRequest request , HttpServletResponse response ) {
52
54
try {
@@ -91,7 +93,7 @@ public void good1(String url, HttpServletRequest request, HttpServletResponse re
91
93
}
92
94
}
93
95
94
- // Non-Spring test cases (UnsafeRequest*Path*)
96
+ // `RequestDispatcher` test cases from non-Spring entry points
95
97
private static final String BASE_PATH = "/pages" ;
96
98
97
99
@ Override
@@ -132,7 +134,6 @@ public void doFilter3(ServletRequest request, ServletResponse response, FilterCh
132
134
}
133
135
}
134
136
135
- // Non-Spring test cases (UnsafeServletRequest*Dispatch*)
136
137
@ Override
137
138
// BAD: Request dispatcher constructed from `ServletContext` without input validation
138
139
protected void doGet (HttpServletRequest request , HttpServletResponse response )
@@ -184,7 +185,7 @@ protected void doPut(HttpServletRequest request, HttpServletResponse response)
184
185
}
185
186
186
187
// BAD: Request dispatcher without path traversal check
187
- protected void doHead2 (HttpServletRequest request , HttpServletResponse response )
188
+ protected void doHead1 (HttpServletRequest request , HttpServletResponse response )
188
189
throws ServletException , IOException {
189
190
String path = request .getParameter ("path" );
190
191
@@ -196,7 +197,7 @@ protected void doHead2(HttpServletRequest request, HttpServletResponse response)
196
197
197
198
// BAD: Request dispatcher with path traversal check that does not decode
198
199
// the user-supplied path; could bypass check with ".." encoded as "%2e%2e".
199
- protected void doHead3 (HttpServletRequest request , HttpServletResponse response )
200
+ protected void doHead2 (HttpServletRequest request , HttpServletResponse response )
200
201
throws ServletException , IOException {
201
202
String path = request .getParameter ("path" );
202
203
@@ -207,7 +208,7 @@ protected void doHead3(HttpServletRequest request, HttpServletResponse response)
207
208
208
209
// BAD: Request dispatcher with path normalization and comparison, but
209
210
// does not decode before normalization.
210
- protected void doHead4 (HttpServletRequest request , HttpServletResponse response )
211
+ protected void doHead3 (HttpServletRequest request , HttpServletResponse response )
211
212
throws ServletException , IOException {
212
213
String path = request .getParameter ("path" );
213
214
@@ -220,7 +221,7 @@ protected void doHead4(HttpServletRequest request, HttpServletResponse response)
220
221
}
221
222
222
223
// BAD: Request dispatcher with negation check and path normalization, but without URL decoding.
223
- protected void doHead5 (HttpServletRequest request , HttpServletResponse response )
224
+ protected void doHead4 (HttpServletRequest request , HttpServletResponse response )
224
225
throws ServletException , IOException {
225
226
String path = request .getParameter ("path" );
226
227
// Since not decoded before normalization, "/%57EB-INF" can remain in the path and pass the `startsWith` check.
@@ -232,7 +233,7 @@ protected void doHead5(HttpServletRequest request, HttpServletResponse response)
232
233
}
233
234
234
235
// BAD: Request dispatcher with path traversal check and single URL decoding; may be vulnerable to double-encoding
235
- protected void doHead7 (HttpServletRequest request , HttpServletResponse response )
236
+ protected void doHead5 (HttpServletRequest request , HttpServletResponse response )
236
237
throws ServletException , IOException {
237
238
String path = request .getParameter ("path" );
238
239
path = URLDecoder .decode (path , "UTF-8" );
@@ -245,9 +246,9 @@ protected void doHead7(HttpServletRequest request, HttpServletResponse response)
245
246
// GOOD: Request dispatcher with path traversal check and URL decoding in a loop to avoid double-encoding bypass
246
247
protected void doHead6 (HttpServletRequest request , HttpServletResponse response )
247
248
throws ServletException , IOException {
248
- String path = request .getParameter ("path" ); // TODO: remove this debugging comment: // v
249
+ String path = request .getParameter ("path" );
249
250
250
- if (path .contains ("%" )){ // TODO: remove this debugging comment: // v.getAnAccess()
251
+ if (path .contains ("%" )){
251
252
while (path .contains ("%" )) {
252
253
path = URLDecoder .decode (path , "UTF-8" );
253
254
}
@@ -259,7 +260,7 @@ protected void doHead6(HttpServletRequest request, HttpServletResponse response)
259
260
}
260
261
261
262
// GOOD: Request dispatcher with URL encoding check and path traversal check
262
- protected void doHead16 (HttpServletRequest request , HttpServletResponse response )
263
+ protected void doHead7 (HttpServletRequest request , HttpServletResponse response )
263
264
throws ServletException , IOException {
264
265
String path = request .getParameter ("path" );
265
266
@@ -270,41 +271,33 @@ protected void doHead16(HttpServletRequest request, HttpServletResponse response
270
271
}
271
272
}
272
273
273
- // TODO: clean-up
274
- // BAD (I added): Request dispatcher with path traversal check and single URL decoding; may be vulnerable to double-encoding
275
- // Tests urlEncoding BarrierGuard "a guard that considers a string safe because it is checked for URL encoding sequences,
276
- // having previously been checked against a block-list of forbidden values."
277
- protected void doHead10 (HttpServletRequest request , HttpServletResponse response )
274
+ // BAD: Request dispatcher without URL decoding before WEB-INF and path traversal checks
275
+ protected void doHead8 (HttpServletRequest request , HttpServletResponse response )
278
276
throws ServletException , IOException {
279
277
String path = request .getParameter ("path" );
280
- if (path .contains ("%" )){ // BAD: wrong check
281
- if (!path .startsWith ("/WEB-INF/" ) && !path .contains (".." )) {
282
- // if (path.contains("%")){ // BAD: wrong check
278
+ if (path .contains ("%" )){ // incorrect check
279
+ if (!path .startsWith ("/WEB-INF/" ) && !path .contains (".." )) {
283
280
request .getServletContext ().getRequestDispatcher (path ).include (request , response ); // $ hasUrlForward
284
- // }
281
+ }
285
282
}
286
283
}
287
- }
288
284
289
- // TODO: clean-up
290
- // "GOOD" (I added): Request dispatcher with path traversal check and single URL decoding; may be vulnerable to double-encoding
291
- // Tests urlEncoding BarrierGuard "a guard that considers a string safe because it is checked for URL encoding sequences,
292
- // having previously been checked against a block-list of forbidden values."
293
- protected void doHead11 (HttpServletRequest request , HttpServletResponse response )
285
+ // GOOD: Request dispatcher with WEB-INF, path traversal, and URL encoding checks
286
+ protected void doHead9 (HttpServletRequest request , HttpServletResponse response )
294
287
throws ServletException , IOException {
295
288
String path = request .getParameter ("path" );
296
289
297
290
if (!path .startsWith ("/WEB-INF/" ) && !path .contains (".." )) {
298
- if (!path .contains ("%" )){ // GOOD: right check
291
+ if (!path .contains ("%" )){ // correct check
299
292
request .getServletContext ().getRequestDispatcher (path ).include (request , response );
300
293
}
301
294
}
302
295
}
303
296
304
297
// GOOD: Request dispatcher with path traversal check and URL decoding in a loop to avoid double-encoding bypass
305
- protected void doHead8 (HttpServletRequest request , HttpServletResponse response )
298
+ protected void doHead10 (HttpServletRequest request , HttpServletResponse response )
306
299
throws ServletException , IOException {
307
- String path = request .getParameter ("path" ); // TODO: remove this debugging comment: // v
300
+ String path = request .getParameter ("path" );
308
301
while (path .contains ("%" )) {
309
302
path = URLDecoder .decode (path , "UTF-8" );
310
303
}
@@ -314,12 +307,12 @@ protected void doHead8(HttpServletRequest request, HttpServletResponse response)
314
307
}
315
308
}
316
309
317
- // TODO: see if can fix?
318
- // FP now....
319
310
// GOOD: Request dispatcher with path traversal check and URL decoding in a loop to avoid double-encoding bypass
320
- protected void doHead9 (HttpServletRequest request , HttpServletResponse response )
311
+ protected void doHead11 (HttpServletRequest request , HttpServletResponse response )
321
312
throws ServletException , IOException {
322
- String path = request .getParameter ("path" ); // v
313
+ String path = request .getParameter ("path" );
314
+ // FP: we don't currently handle the scenario where the
315
+ // `path.contains("%")` check is stored in a variable.
323
316
boolean hasEncoding = path .contains ("%" );
324
317
while (hasEncoding ) {
325
318
path = URLDecoder .decode (path , "UTF-8" );
0 commit comments