@@ -5,78 +5,51 @@ public class UnsafeServletRequestDispatch extends HttpServlet {
5
5
protected void doGet (HttpServletRequest request , HttpServletResponse response )
6
6
throws ServletException , IOException {
7
7
{
8
- // GOOD: whitelisted URI
8
+ ServletConfig cfg = getServletConfig ();
9
+ ServletContext sc = cfg .getServletContext ();
10
+
11
+ // GOOD: check for an explicitly permitted URI
12
+ String action = request .getParameter ("action" );
9
13
if (action .equals ("Login" )) {
10
- ServletContext sc = cfg .getServletContext ();
11
14
RequestDispatcher rd = sc .getRequestDispatcher ("/Login.jsp" );
12
15
rd .forward (request , response );
13
- }
14
- }
16
+ }
15
17
16
- {
17
- // BAD: Request dispatcher constructed from `ServletContext` without input validation
18
+ // BAD: no URI validation
18
19
String returnURL = request .getParameter ("returnURL" );
19
- ServletConfig cfg = getServletConfig ();
20
-
21
- ServletContext sc = cfg .getServletContext ();
22
20
RequestDispatcher rd = sc .getRequestDispatcher (returnURL );
23
21
rd .forward (request , response );
24
- }
25
22
26
- {
27
- // BAD: Request dispatcher without path traversal check
23
+ // A sample payload "/pages/welcome.jsp/../WEB-INF/web.xml" can bypass the `startsWith` check
24
+ // The payload "/pages/welcome.jsp/../../%57EB-INF/web.xml" can bypass the check as well since RequestDispatcher will decode `%57` as `W`
28
25
String path = request .getParameter ("path" );
29
26
30
- // A sample payload "/pages/welcome.jsp/../WEB-INF/web.xml" can bypass the `startsWith` check
31
- // The payload "/pages/welcome.jsp/../../%57EB-INF/web.xml" can bypass the check as well since RequestDispatcher will decode `%57` as `W`
27
+ // BAD: no check for path traversal
32
28
if (path .startsWith (BASE_PATH )) {
33
29
request .getServletContext ().getRequestDispatcher (path ).include (request , response );
34
30
}
35
- }
36
- }
37
-
38
- {
39
- // GOOD: Request dispatcher with path traversal check
40
- String path = request .getParameter ("path" );
41
-
42
- if (path .startsWith (BASE_PATH ) && !path .contains (".." )) {
43
- request .getServletContext ().getRequestDispatcher (path ).include (request , response );
44
- }
45
- }
46
-
47
- {
48
- // GOOD: Request dispatcher with path normalization
49
- String path = request .getParameter ("path" );
50
- Path requestedPath = Paths .get (BASE_PATH ).resolve (path ).normalize ();
51
-
52
- // /pages/welcome.jsp/../../WEB-INF/web.xml becomes /WEB-INF/web.xml
53
- // /pages/welcome.jsp/../../%57EB-INF/web.xml becomes /%57EB-INF/web.xml
54
- if (requestedPath .startsWith (BASE_PATH )) {
55
- request .getServletContext ().getRequestDispatcher (requestedPath .toString ()).forward (request , response );
56
- }
57
- }
58
31
59
- {
60
- // BAD: Request dispatcher with improper negation check and without url decoding
61
- String path = request .getParameter ( " path" );
62
- Path requestedPath = Paths . get ( BASE_PATH ). resolve ( path ). normalize ();
32
+ // GOOD: To check there won't be unexpected path traversal, we can check for any `..` sequences and whether the URI starts with a given web root path.
33
+ if ( path . startsWith ( BASE_PATH ) && ! path . contains ( ".." )) {
34
+ request .getServletContext (). getRequestDispatcher ( path ). include ( request , response );
35
+ }
63
36
64
- if (!requestedPath .startsWith ("/WEB-INF" ) && !requestedPath .startsWith ("/META-INF" )) {
65
- request .getServletContext ().getRequestDispatcher (requestedPath .toString ()).forward (request , response );
66
- }
67
- }
37
+ // GOOD: Or alternatively we can use Path.normalize and check whether the URI starts with a given web root path.
38
+ Path requestedPath = Paths .get (BASE_PATH ).resolve (path ).normalize ();
39
+ if (requestedPath .startsWith (BASE_PATH )) {
40
+ request .getServletContext ().getRequestDispatcher (requestedPath .toString ()).forward (request , response );
41
+ }
68
42
69
- {
70
- // GOOD: Request dispatcher with path traversal check and url decoding
71
- String path = request .getParameter ("path" );
72
- boolean hasEncoding = path .contains ("%" );
73
- while (hasEncoding ) {
74
- path = URLDecoder .decode (path , "UTF-8" );
75
- hasEncoding = path .contains ("%" );
76
- }
43
+ // GOOD: Or alternatively ensure URL encoding is removed and then check for any `..` sequences.
44
+ boolean hasEncoding = path .contains ("%" );
45
+ while (hasEncoding ) {
46
+ path = URLDecoder .decode (path , "UTF-8" );
47
+ hasEncoding = path .contains ("%" );
48
+ }
77
49
78
- if (!path .startsWith ("/WEB-INF/" ) && !path .contains (".." )) {
79
- request .getServletContext ().getRequestDispatcher (path ).include (request , response );
50
+ if (!path .startsWith ("/WEB-INF/" ) && !path .contains (".." )) {
51
+ request .getServletContext ().getRequestDispatcher (path ).include (request , response );
52
+ }
80
53
}
81
54
}
82
55
}
0 commit comments