Protecting JSPs from direct access in Struts
By: Emiley J in Struts Tutorials on 2007-10-01
According to the Model 2 paradigm, the view is always served by the controller and should not be requested explicitly from any other view. In reality a JSP can always navigate to another JSP when the JSPs are placed anywhere in a WAR other than the WEB-INF directory (or its sub-directories). Similarly a user can type in the name of the JSP in the URL bar and invoke the JSP. The web application specification does not disallow such access. Actually this makes sense. The specification should not prevent anybody from coding using the Model 1 paradigm. Consequently your JSPs are exposed to the external world for nosy users to cause unnecessary problems, for hackers to exploit any vulnerability in the system. If you are wondering what the problem is with allowing direct access to JSPs, well, here are some.
A nosy user might attempt to guess the JSP name by the operation performed in that page or request parameters or worse – if the page author used html comment tag for SCM and code comments instead of the JSP comments. Armed with this information, the user attempts to access the JSPs directly. A JSP as you know is a view and it displays information based on model objects stored in one of the four scopes – page, request, session or application, the first three being the most common. These objects are created by the back end presentation and business logic and made available for the JSP to act upon. When the JSP is accessed out of context or out of order, the required model objects may not exist in the appropriate scope and consequently almost always leads to the exceptional situations in the JSP code.
It is not common to perform null checks in every bit of code in the JSP tags, scriptlets and other helper classes. These checks are generally limited to interfaces and boundaries between modules and not later on. For instance, in a typical Model 2 scenario, when the model object cannot be created for some reason, the controller instead takes alternate route and displays an alternate view corresponding to the null model object. This assumption of model objects being not null in the main path of the presentation logic and view highly simplifies the coding. In fact when the system is accessed as intended, everything works smoothly. However whenever somebody tries to access the views out of order, all hell breaks lose. Every view starts throwing NullPointerExceptions, IllegalArgumentExceptions and other unchecked and checked exceptions depending on how the JSP page and its tags and scriptlets are authored. This is exactly what a nosy user is trying out.
The implications are even more serious when a malicious user tries to find weak points in the design to bring the system down to its knees. The first thing that might occur is to put checks for nulls and unintended access in the system. Invariably, this is nothing but a collection of if-else blocks in every part of the JSP page making it messy and buggy to maintain.
Two prominent alternatives exist. Let us look the easiest one first. As we glossed over earlier, the servlet specification explicitly states that contents located in the WEB-INF and its sub-directories are protected from outside access.
Let us take a simple example to illustrate this. All contents located in a WAR belong to the same protection domain. A protection domain is a set of entities known (or assumed) to trust each other. Consequently any resource within a WAR can access resources located under WEB-INF directory without restrictions. JSP is also a resource and thus any class within the same WAR can forward to a JSP under WEB-INF. (This part is not explicitly stated in the specification) However when the request originates outside the container, it does not belong to the protection domain (at least not until it is authenticated) and hence cannot access the protected resource under WEB-INF. Thus putting all JSPs under the WEB-INF directly or as sub-directories if needed is the easiest and also the best way of protecting direct access to JSPs. What if the hyperlink in one of your page wants to really just forward to another JSP? Is that disallowed as well? Yeah! You cannot have different rules in your system right? However there is a way around.
Consider the case when a hyperlink in page A needs to forward request to page B. Instead of directly forwarding to page B, which is disallowed, you can put the following entry in the struts-config.xml
<action path="/gotoPageB"
parameter="/WEB-INF/pageB.jsp"
type="org.apache.struts.actions.ForwardAction" />
On the pageA, the hyperlink can point to "pageB.do" is suffix mapping is used or some other path is path mapping is used. Either ways, the ActionMapping shown above is picked up and as its type indicates, the action is just a ForwardAction, which as the name suggest is a forward. However since the forward is occurring from within the container, (in the protection domain) it is allowed.
A question might be popping up in your mind. The technique just highlighted is the easiest and also supposedly the best. Why do I need anything lesser than best? The answer is not all containers support the behavior just mentioned. As we stated earlier, since the specification is clear about not letting direct access to resources under WEB-INF, all J2EE compliant application servers implement it. However, the second part is not stated in the specification and consequently it is the vendor's prerogative to implement it or not. Certain providers do (For e.g. Tomcat) and others don't (For e.g. WebLogic). Hence we have to have an alternate mechanism for the less fortunate ones. This one is not difficult either. Instead of putting the JSPs underneath WEB-INF, they can stay wherever they are. The following entries are added to the web.xml.
<security-constraint>
<web-resource-collection>
<web-resource-name>Deny Direct Access</web-resource-name>
<description>
Deny direct access to JSPs by associating them with denied role
</description>
<url-pattern>*.jsp</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>Denied</role-name>
</auth-constraint>
</security-constraint>
<security-role>
<role-name>Denied</role-name>
</security-role>
First, all the url patterns ending with suffix ".jsp" are associated with a Role named "Denied". Any user who wants to access the JSP pages directly should be in that role. We further ensure that no user of the system is in that Role. Role and user association is done depending on your implementation of authentication and authorization. For instance, if you are using LDAP as the user persistence mechanism, then the users, their passwords and Roles are stored in LDAP. If you ensure nobody gets the Denied role, then you have effectively prevented everyone from directly accessing the JSPs. You will still have to have the ForwardAction as shown earlier in this section if you have situation when page A needs to just navigate to page B. The internal forwards to other JSPs using RequestDispatcher are okay because the container does not intercept and cross check internal forwards even though the url-pattern matches the ones in web.xml.
NOTE: The default pagePattern and forwardPattern values for <controller> element in struts-config.xml are $M$P, where $M is replaced with the module prefix and the $P is replaced with the path attribute of the selected forward. If you place your JSP files under WEB-INF for access protection, you have to set the pagePattern and forwardPattern attributes of the <controller> element in the struts-config.xml to /WEB-INF/$M$P to tell Struts to construct the paths correctly.
Add Comment
This policy contains information about your privacy. By posting, you are declaring that you understand this policy:
- Your name, rating, website address, town, country, state and comment will be publicly displayed if entered.
- Aside from the data entered into these form fields, other stored data about your comment will include:
- Your IP address (not displayed)
- The time/date of your submission (displayed)
- Your email address will not be shared. It is collected for only two reasons:
- Administrative purposes, should a need to contact you arise.
- To inform you of new comments, should you subscribe to receive notifications.
- A cookie may be set on your computer. This is used to remember your inputs. It will expire by itself.
This policy is subject to change at any time and without notice.
These terms and conditions contain rules about posting comments. By submitting a comment, you are declaring that you agree with these rules:
- Although the administrator will attempt to moderate comments, it is impossible for every comment to have been moderated at any given time.
- You acknowledge that all comments express the views and opinions of the original author and not those of the administrator.
- You agree not to post any material which is knowingly false, obscene, hateful, threatening, harassing or invasive of a person's privacy.
- The administrator has the right to edit, move or remove any comment for any reason and without notice.
Failure to comply with these rules may result in being banned from submitting further comments.
These terms and conditions are subject to change at any time and without notice.
- Data Science
- Android
- React Native
- AJAX
- ASP.net
- C
- C++
- C#
- Cocoa
- Cloud Computing
- HTML5
- Java
- Javascript
- JSF
- JSP
- J2ME
- Java Beans
- EJB
- JDBC
- Linux
- Mac OS X
- iPhone
- MySQL
- Office 365
- Perl
- PHP
- Python
- Ruby
- VB.net
- Hibernate
- Struts
- SAP
- Trends
- Tech Reviews
- WebServices
- XML
- Certification
- Interview
categories
Related Tutorials
Handling Duplicate Form Submissions in Struts
Guidelines for Struts Application Development
Configuring JDBC DataSources in Struts
When is the best time to validate input in Struts
Simple example of using the requiredif Validator rule in Struts
How to prepopulate a form in Struts
Using JavaScript to submit a form in Struts
FAQ: Why are my checkboxes not being set from ON to OFF?
FAQ: Why was reload removed from Struts (since 1.1)?
Comments