What is it and why should I care?
Java Server Pages (JSPs) is an extremely common UI view technology used in J2EE development. JSPs represent the interface the end user interacts with while using an application. JSPs also usually include some business logic, and frequently there are portions of a page protected by some authorization constraints. Additionally, there are many times other protections in request handling (controller) code that perform some authorization before forwarding users to a given JSP. Bottom line, there is important logic (and at times data) stored in JSPs that shouldn’t be generally accessible to end users without going through the appropriate controls to gain access to them.
Knowing that these resources are important to the application, we’d certainly like to protect them. In general, modern applications rely on frameworks that use an MVC model for accessing an application. What that practically means regarding JSPs is that there is no direct access to the JSP during normal use of the application. You make a request to some type of controller or handler that performs some business logic and then internally forwards to a JSP for rendering. This means JSPs are generally no longer directly accessed, at least on purpose. However, if you store your JSPs in an area accessible to the web without putting them in the WEB-INF (same place where your web.xml goes) directory, they can be directly browsed by users (unless you have other protections in place). This means your pages will most likely break functionally (since they won’t have certain data they are expecting to come from the controller), and they will often times not have the appropriate authorizations performed since those are often expected to occur when a user follows the path through the controller.
Note: These same points could be made about certain types of configuration files, scripts and other types of data included in web applications, but JSPs are generally recognized as the most common resource type that is able to be force-browsed by the end user and contains important data. Also, configuration files for many frameworks work only when they are stored in WEB-INF, simplifying the issue there by forcing you to do it right.
What should I do about it?
The Servlet Specification defines that the WEB-INF directory of a deployed application is not to be directly accessible by external users. In other words, if a request is made for a resource in WEB-INF, it will be rejected. The only way this won’t be the case is if there is a bug in the application server running your application.
For this reason, you should store your JSPs in WEB-INF. This way, your application will still be able to use them, since forwarding to a resource in WEB-INF happens server-side and doesn’t present an access issue. Additionally, you prevent external users from being able to request them successfully by force browsing to them.
One thing to be aware of is that code that does file manipulation (read, write, move, etc.) on server-side files is still able to access the WEB-INF directory. This means there are still plenty of bugs out there where you can do directory traversal to read the web.xml file in the WEB-INF directory. The WEB-INF directory does prevent access to external direct requests, but not to code that runs server-side – definitely something to watch out for.
Storing your JSPs in the WEB-INF directory is a very simple and effective mechanism that offers protection against forced browsing attempts, and you can and should use it to provide an additional layer of protection to your applications.