@@ -5,78 +5,51 @@ public class UnsafeServletRequestDispatch extends HttpServlet {
55 protected void doGet (HttpServletRequest request , HttpServletResponse response )
66 throws ServletException , IOException {
77 {
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" );
913 if (action .equals ("Login" )) {
10- ServletContext sc = cfg .getServletContext ();
1114 RequestDispatcher rd = sc .getRequestDispatcher ("/Login.jsp" );
1215 rd .forward (request , response );
13- }
14- }
16+ }
1517
16- {
17- // BAD: Request dispatcher constructed from `ServletContext` without input validation
18+ // BAD: no URI validation
1819 String returnURL = request .getParameter ("returnURL" );
19- ServletConfig cfg = getServletConfig ();
20-
21- ServletContext sc = cfg .getServletContext ();
2220 RequestDispatcher rd = sc .getRequestDispatcher (returnURL );
2321 rd .forward (request , response );
24- }
2522
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`
2825 String path = request .getParameter ("path" );
2926
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
3228 if (path .startsWith (BASE_PATH )) {
3329 request .getServletContext ().getRequestDispatcher (path ).include (request , response );
3430 }
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- }
5831
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+ }
6336
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+ }
6842
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+ }
7749
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+ }
8053 }
8154 }
8255}
0 commit comments