1+ package com .example ;
2+
13import java .io .InputStream ;
24import java .io .IOException ;
35import java .nio .file .Path ;
1315import javax .servlet .ServletContext ;
1416
1517public class UnsafeResourceGet extends HttpServlet {
18+ private static final String BASE_PATH = "/pages" ;
19+
1620 @ Override
1721 // BAD: getResource constructed from `ServletContext` without input validation
1822 protected void doGet (HttpServletRequest request , HttpServletResponse response )
@@ -23,6 +27,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response)
2327 ServletConfig cfg = getServletConfig ();
2428 ServletContext sc = cfg .getServletContext ();
2529
30+ // A sample request /fake.jsp/../WEB-INF/web.xml can load the web.xml file
2631 URL url = sc .getResource (requestUrl );
2732
2833 InputStream in = url .openStream ();
@@ -43,13 +48,15 @@ protected void doGetGood(HttpServletRequest request, HttpServletResponse respons
4348 ServletContext sc = cfg .getServletContext ();
4449
4550 Path path = Paths .get (requestUrl ).normalize ().toRealPath ();
46- URL url = sc .getResource (path .toString ());
51+ if (path .startsWith (BASE_PATH )) {
52+ URL url = sc .getResource (path .toString ());
4753
48- InputStream in = url .openStream ();
49- byte [] buf = new byte [4 * 1024 ]; // 4K buffer
50- int bytesRead ;
51- while ((bytesRead = in .read (buf )) != -1 ) {
52- out .write (buf , 0 , bytesRead );
54+ InputStream in = url .openStream ();
55+ byte [] buf = new byte [4 * 1024 ]; // 4K buffer
56+ int bytesRead ;
57+ while ((bytesRead = in .read (buf )) != -1 ) {
58+ out .write (buf , 0 , bytesRead );
59+ }
5360 }
5461 }
5562
@@ -63,6 +70,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
6370 ServletConfig cfg = getServletConfig ();
6471 ServletContext sc = cfg .getServletContext ();
6572
73+ // A sample request /fake.jsp/../WEB-INF/web.xml can load the web.xml file
6674 InputStream in = request .getServletContext ().getResourceAsStream (requestPath );
6775 byte [] buf = new byte [4 * 1024 ]; // 4K buffer
6876 int bytesRead ;
@@ -89,4 +97,81 @@ protected void doPostGood(HttpServletRequest request, HttpServletResponse respon
8997 }
9098 }
9199 }
100+
101+ @ Override
102+ // BAD: getResource constructed from `Class` without input validation
103+ protected void doHead (HttpServletRequest request , HttpServletResponse response )
104+ throws ServletException , IOException {
105+ String requestUrl = request .getParameter ("requestURL" );
106+ ServletOutputStream out = response .getOutputStream ();
107+
108+ // A sample request /fake.jsp/../../../WEB-INF/web.xml can load the web.xml file
109+ // Note the class is in two levels of subpackages and `Class.loadResource` starts from its own directory
110+ URL url = getClass ().getResource (requestUrl );
111+
112+ InputStream in = url .openStream ();
113+ byte [] buf = new byte [4 * 1024 ]; // 4K buffer
114+ int bytesRead ;
115+ while ((bytesRead = in .read (buf )) != -1 ) {
116+ out .write (buf , 0 , bytesRead );
117+ }
118+ }
119+
120+ // GOOD: getResource constructed from `Class` with input validation
121+ protected void doHeadGood (HttpServletRequest request , HttpServletResponse response )
122+ throws ServletException , IOException {
123+ String requestUrl = request .getParameter ("requestURL" );
124+ ServletOutputStream out = response .getOutputStream ();
125+
126+ Path path = Paths .get (requestUrl ).normalize ().toRealPath ();
127+ if (path .startsWith (BASE_PATH )) {
128+ URL url = getClass ().getResource (path .toString ());
129+
130+ InputStream in = url .openStream ();
131+ byte [] buf = new byte [4 * 1024 ]; // 4K buffer
132+ int bytesRead ;
133+ while ((bytesRead = in .read (buf )) != -1 ) {
134+ out .write (buf , 0 , bytesRead );
135+ }
136+ }
137+ }
138+
139+ @ Override
140+ // BAD: getResourceAsStream constructed from `ClassLoader` without input validation
141+ protected void doPut (HttpServletRequest request , HttpServletResponse response )
142+ throws ServletException , IOException {
143+ String requestPath = request .getParameter ("requestPath" );
144+ ServletOutputStream out = response .getOutputStream ();
145+
146+ ServletConfig cfg = getServletConfig ();
147+ ServletContext sc = cfg .getServletContext ();
148+
149+ // A sample request /fake.jsp/../../../WEB-INF/web.xml can load the web.xml file
150+ // Note the class is in two levels of subpackages and `ClassLoader.getResourceAsStream` starts from its own directory
151+ InputStream in = getClass ().getClassLoader ().getResourceAsStream (requestPath );
152+ byte [] buf = new byte [4 * 1024 ]; // 4K buffer
153+ int bytesRead ;
154+ while ((bytesRead = in .read (buf )) != -1 ) {
155+ out .write (buf , 0 , bytesRead );
156+ }
157+ }
158+
159+ // GOOD: getResourceAsStream constructed from `ClassLoader` with input validation
160+ protected void doPutGood (HttpServletRequest request , HttpServletResponse response )
161+ throws ServletException , IOException {
162+ String requestPath = request .getParameter ("requestPath" );
163+ ServletOutputStream out = response .getOutputStream ();
164+
165+ ServletConfig cfg = getServletConfig ();
166+ ServletContext sc = cfg .getServletContext ();
167+
168+ if (!requestPath .contains (".." ) && requestPath .startsWith ("/trusted" )) {
169+ InputStream in = getClass ().getClassLoader ().getResourceAsStream (requestPath );
170+ byte [] buf = new byte [4 * 1024 ]; // 4K buffer
171+ int bytesRead ;
172+ while ((bytesRead = in .read (buf )) != -1 ) {
173+ out .write (buf , 0 , bytesRead );
174+ }
175+ }
176+ }
92177}
0 commit comments