1- public class UnsafeServletRequestDispatch extends HttpServlet {
2- private static final String BASE_PATH = "/pages" ;
3-
4- @ Override
5- protected void doGet (HttpServletRequest request , HttpServletResponse response )
6- throws ServletException , IOException {
7- {
8- ServletConfig cfg = getServletConfig ();
9- ServletContext sc = cfg .getServletContext ();
10-
11- // GOOD: check for an explicitly permitted URI
12- String action = request .getParameter ("action" );
13- if (action .equals ("Login" )) {
14- RequestDispatcher rd = sc .getRequestDispatcher ("/Login.jsp" );
15- rd .forward (request , response );
16- }
17-
18- // BAD: no URI validation
19- String returnURL = request .getParameter ("returnURL" );
20- RequestDispatcher rd = sc .getRequestDispatcher (returnURL );
21- rd .forward (request , response );
22-
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`
25- String path = request .getParameter ("path" );
26-
27- // BAD: no check for path traversal
28- if (path .startsWith (BASE_PATH )) {
29- request .getServletContext ().getRequestDispatcher (path ).include (request , response );
30- }
31-
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- }
36-
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- }
42-
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- }
49-
50- if (!path .startsWith ("/WEB-INF/" ) && !path .contains (".." )) {
51- request .getServletContext ().getRequestDispatcher (path ).include (request , response );
52- }
53- }
54- }
55- }
1+ // BAD: no URI validation
2+ String returnURL = request .getParameter ("returnURL" );
3+ RequestDispatcher rd = sc .getRequestDispatcher (returnURL );
4+ rd .forward (request , response );
5+
6+ // GOOD: check for a trusted prefix, ensuring path traversal is not used to erase that prefix:
7+ // (alternatively use `Path.normalize` instead of checking for `..`)
8+ if (!returnURL .contains (".." ) && returnURL .hasPrefix ("/pages" )) { ... }
9+ // Also GOOD: check for a forbidden prefix, ensuring URL-encoding is not used to evade the check:
10+ // (alternatively use `URLDecoder.decode` before `hasPrefix`)
11+ if (returnURL .hasPrefix ("/internal" ) && !returnURL .contains ("%" )) { ... }
0 commit comments