Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

XSS vulnarability detection tool for JSP

4.94/5 (11 votes)
30 Jul 2013CPOL7 min read 49.3K   537  
A tool to detect unsafe use of EL which leads to XSS vulnarability.

Introduction

Java Server Pages 2.0 specification introduced a new feature with it support for Expression Language (EL) through the JSP page. This enhancement really made it simple to access data stored in JavaBean components or other java objects such as request, session, application, etc., anywhere in the page. In earlier specifications, this support was restricted to JSTL tags only and required the use of JSTL tags such as c:out, fmt:formatDate , etc., to access such components, resulting in a more cluttered code. Thanks to JSP 2.0 spec., this clutter is now a history. However this support also resulted in many people using it in an improper manner, making their application susceptible to an attack called XSS attack. This article presents possible solutions to defend against this attack and also a tool to find out improper usage of EL in JSP pages.

XSS Vulnerability

According to Wikipedia, XSS (Cross Site Scripting) is a type of attack which enables attackers to inject client-side script into web pages viewed by other users. A cross-site scripting vulnerability may be used by attackers to bypass access controls such as the same origin policy. The effect may range from a petty nuisance to a significant security risk, depending on the sensitivity of the data handled by the vulnerable site and the nature of any security mitigation implemented by the site's owner. There are two major flavors of XSS, persistent and non-persistent. A very simple use case for persistent XSS attack is described below:

  1. User A visits a social networking site which is vulnerable to XSS and accesses some page, say a page to add a new post.
  2. Instead of entering some textual message, user enters an HTML/JavaScript block in this message field and hits Save. Let's say, a JavaScript block.
  3. Site stores the message as is.
  4. User B visits the message page. Upon viewing the message the JavaScript executes and possibly sends the cookie and other headers to a remote site created by User A.
  5. User A can now use this information to hack session of user B.

JSP EL and XSS Exploit

Let's say that the above site is developed using JSP and the code for outputting the message form looks something like the code shown below:

HTML
<%@ page contentType="text/html;charset=utf-8" language="java" buffer="none" pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="<a href="http://java.sun.com/jsp/jstl/core">http://java.sun.com/jsp/jstl/core</a>" %>
<%@ taglib prefix="fmt" uri="<a href="http://java.sun.com/jsp/jstl/fmt">http://java.sun.com/jsp/jstl/fmt</a>" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
<meta http-equiv="X-UA-Compatible" content="IE=edge"></meta>
<meta http-equiv="Expires" content="0"></meta>
<meta http-equiv="Pragma" content="no-cache"></meta>
<meta http-equiv="Cache-Control" content="no-cache"></meta>
<meta http-equiv="Pragma-directive" content="no-cache"></meta>
<meta http-equiv="cache-directive" content="no-cache"></meta>
<meta name="owner" content="Abra Ka Dabra"></meta>
<meta name="copyright" content="(c) 2020, Future Coding"></meta>
<title>Edit Message Form</title>
<link rel="stylesheet" type="text/css" href="static/css/styles.css"></link>
<link rel="stylesheet" type="text/css" href="static/css/percent-column-system-min.css"></link>
<script type="text/javascript" src="static/js/jquery/jquery-1.9.1.min.js"></script>
</head>
<body>
    <div class="pageTitle">Edit Message Form</div>
    <div id="frmDiv">
        <form name="frmMsg" id="frmMsg" method="post" action="editform.do">
            <div>
                <label for="txtSubject">Subject :</label><br>
                <input type="text" id="txtSubject" name="txtSubject" 
                    size="40" maxlength="80" value="${msgBean.subject}"/>
            </div>
            <div>
                <label for="txtBody">Message :</label><br>
                <textarea rows="10" cols="72" id="txtBody" 
                      name="txtBody">${msgBean.body}</textarea>
            </div>
            <div class="buttonbar">
                <button type="button" id="btnPost" 
                   name="btnPost" value="Post" onclick="postMessage()"/>
            </div>
            <input type="hidden" id="msgId" 
                name="msgId" value="${msgBean.msgId}"/>
        </form>
    </div>
</body>
</html>

So what thing in the code causes this attack? There are multiple reasons. The code to save the message saves the message as is without sanitizing it first. However this may or may not be possible if you want to support rich messages. The retrieved message text is sent as is without sanitizing (HTML Escaping) it first. As seen in the above code the EL is directly embedded in the HTML element. What really happens behind the scenes is that upon encountering the EL the servlet simply evaluates the expression and embeds the result in the output stream. E.g., in Tomcat, the line which outputs the message body gets translated as shown below:

Java
out.write("\r\n");
out.write("<textarea rows=\"10\" cols=\"72\" id=\"txtBody\" name=\"txtBody\">");
out.write((java.lang.String) org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${msgBean.body}", java.lang.String.class,
          (PageContext) _jspx_page_context, null, false));
out.write("<textarea>");

The method out.write  does not sanitize (encodes/escapes) the value. As a result browsers see the code as a valid script block and executes the script block. The script block in such a scenario might be written to gather cookie(s) and hidden field(s) and post this data to a remote site using AJAX, thus allowing the attacker to gain access to the user's session.

Possible Solutions

There are multiple solutions to tackle this problem and safeguard your site from XSS attacks. These are outlined below:

  1. Turn off EL  support for all pages. This is done by putting the following entries in web.xml:
  2. XML
    <jsp-config>
        <!-- Set to true to disable JSP scriptiing syntax -->
        <jsp-property-group>
            <url-pattern>*.jsp</url-pattern>
            <scripting-invalid>false</scripting-invalid>
        </jsp-property-group>
        <!-- Set to true to disable Expression Language (EL) syntax -->
        <jsp-property-group>
            <url-pattern>*.jsp</url-pattern>
            <el-ignored>false</el-ignored>
        </jsp-property-group>
    </jsp-config>
  3. Turn on EL  support for a specific page. This is done by specifying the isELIgnored attribute in the page directive of the concerned page.
  4. HTML
    <%@ page isELIgnored ="true|false" %>
  5. Never use EL expressions directly. Instead use the c:out tag to output values. c:out by default escapes the outputted value. This results in the browser rendering the code as HTML text rather than executing it. E.g., the lines outputting the message fields can be re-written as shown below:
  6. HTML
    <div>
        <label for="txtSubject">Subject :</label><br>
        <input type="text" id="txtSubject" name="txtSubject" size="40" 
             maxlength="80" value="<c:out value="${msgBean.subject}"/>"/>
    </div>
    <div>
        <label for="txtBody">Message :</label><br>
        <textarea rows="10" cols="72" id="txtBody" 
          name="txtBody"><c:out value="${msgBean.body}"/></textarea>
    </div>
    <div class="buttonbar">
        <button type="button" id="btnPost" name="btnPost" 
                  value="Post" onclick="postMessage()"/>
    </div>
    <input type="hidden" id="msgId" name="msgId" 
      value="<c:out value="${msgBean.msgId}"/>"/>
  7. If you do not want to use an extra tag then you can use the escapeXML JSTL function. The above code in this case can be re-written as shown below:
  8. HTML
    <div>
        <label for="txtSubject">Subject :</label><br>
        <input type="text" id="txtSubject" name="txtSubject" 
          size="40" maxlength="80" value="${fn:escapeXml(msgBean.subject)}"/>
    </div>
    <div>
        <label for="txtBody">Message :</label><br>
        <textarea rows="10" cols="72" id="txtBody" 
          name="txtBody">${fn:escapeXml(msgBean.body)}</textarea>
    </div>
    <div class="buttonbar">
        <button type="button" id="btnPost" name="btnPost" 
          value="Post" onclick="postMessage()"/>
    </div>
    <input type="hidden" id="msgId" name="msgId" 
      value="${fn:escapeXml(msgBean.msgId)}"/>
  9. Starting with JSP 2.1 it is now possible to register an ELResolver, which can escape the EL values. This ELResolver is registered by a custom listener, which is configured via web.xml. The only downside of this approach is that all EL values are escaped and to really output the custom HTML you will have to either use the Scriplet or use JSP Expression. Yet another way will be to write a custom tag and let it output the unescaped text. More details on this can be found in a nice article written by Chin Huang. The corresponding code is available in a repository located on GitHub.

The Tool

I have created a small tool based on the Jasper Compiler to detect unsafe EL expression usage across JSP pages. As you might be aware in a Servlet Container there is no direct mechanism to run JSP. So the servlet container first converts a JSP page into a servlet and then this servlet gets registered automatically to handle the appropriate URLs. Under Tomcat this translation is done by the Jasper Compiler (org.apache.jasper.compiler.Compiler). The JSP page parsing is done by the Parser class (org.apache.jasper.compiler.Parser) and finally the servlet code is generated by the Generator class (org.apache.jasper.compiler.Generator). The Parser class  parses the page and outputs a list containing nodes. Each node is an internal data representation of a JSP page or a JSP document (XML). The Generator class uses a Node visitor for traversing the node list in recursive manner and generates the servlet code. More details on the various types of nodes can be found in the Jasper Compiler documentation located here.

I have used the Jasper Compiler corresponding to Tomcat version 6.0.36. Although this tool never actually compiles the JSP page it still creates the Compiler class instance. This is required as the internal design of the parser requires a reference to the Compiler instance. The JspCompilationContext class serves as a place holder for various things that are used throughout the JSP Engine. The reason for placing all my classes in the org.apache.jasper.compiler package is because the ParserController, Parser, Node, NodeVisitor classes have a package scope and are not usable outside this package. The actual validation in this case is performed by the NodeVisitor class (org.apache.jasper.compiler.NodeVisitor). Apart from flagging the unsafe use of EL this tool also detects the use of Scriplets and flags those as errors.

Using the Tool

Being a Java based tool it requires Java JRE 6.0 or above. Like any Java utility the tool is run from the command prompt. Before running the tool make sure that the classpath is set to include all the runtime dependencies mentioned under Tool Dependencies. The command line for running the tool is

java -cp %CLASS_PATH% org.apache.jasper.compiler.JSPValidator -root <ROOT_DIR> -skipPath 
   <PATTERNS> -libs <LIB_DIR> -ignoreTags <IGNORE_TAGS> reportFile <REPORT_OUTPUT_FILE>

where

  1. CLASS_PATH - Represents a list of runtime dependencies (jars) and the tool jar as well, separated by File.pathSeperator. E.g., lib/*;build/dist/jspvalidator-1.0.3.jar.
  2. ROOT_DIR - Represents the root folder containing all the jsp, jspf, jspx files.
  3. PATTERNS - Represents a list of Ant like file name or folder name patterns separated by File.pathSeperator.
  4. LIB_DIR - Represents the folder containing the additional jars, referenced in the JSP pages either via the import directive or the taglib directive. 
  5. IGNORE_TAGS - A comma separated list of XML qualified tag names. E.g., "c:out, spring:message".
  6. REPORT_OUTPUT_FILE - The full path and name of the file in which scan results are printed.

Tool Dependencies

The tool has the following runtime dependencies other than the Java runtime.

Jar NamePurpose
commons-cli-1.2.jarCommand line parsing utility
commons-lang-2.6.jarCommons Helper utility for java.lang API
commons-io-2.4.jarCommons IO utility
jasper-6.0.36.jarJasper Compiler
jasper-el-6.0.36.jarJasper EL Support
servlet-api-2.4.jarThe Servlet API reference implementation
jsp-api-2.1.jarThe JSP API reference implementation
juli-6.0.36.jarThe logging support
ecj-4.2.2.jarThe logging support

History

  1. March 06, 2013 - Initial release.
  2. March 29, 2013 - Added support to scan attributes for custom tags, ability to ignore tags, and ability to ignore files.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)