Click here to Skip to main content
15,893,588 members
Articles / Programming Languages / Java

XSS vulnarability detection tool for JSP

Rate me:
Please Sign up or sign in to vote.
4.94/5 (11 votes)
30 Jul 2013CPOL7 min read 48.2K   536   8  
A tool to detect unsafe use of EL which leads to XSS vulnarability.
/*----------------------------------------------------------------------------------------------------------------------
 * PACKAGE  : org.apache.jasper.compiler
 * FILE     : NodeVisitor.java
 * CREATED  : Mar 1, 2013 10:57:11 AM
 * COPYRIGHT: Copyright (c) 2008, Fundtech INDIA Ltd.
 *--------------------------------------------------------------------------------------------------------------------*/
package org.apache.jasper.compiler;

import org.apache.commons.lang.StringUtils;
import org.apache.jasper.JasperException;
import org.apache.jasper.compiler.Node.CustomTag;
import org.apache.jasper.compiler.Node.ELExpression;
import org.apache.jasper.compiler.Node.Expression;
import org.apache.jasper.compiler.Node.JspBody;
import org.apache.jasper.compiler.Node.UninterpretedTag;
import org.apache.jasper.compiler.Node.Visitor;
import org.freeware.fileutils.TextFileUtils;
import org.xml.sax.Attributes;

/**
 * The node visitor class
 * @author Prasad P. Khandekar
 * @version $Id$
 */
public class NodeVisitor extends Visitor
{
	private String[] _arrSkipTags;
	private TextFileUtils _txtWriter;

	/**
	 * Creates a new visitor telling it the tags for which attributes can have unsafe EL.    
	 * @param skipTags a comma separated tag list 
	 */
	public NodeVisitor(String skipTags, TextFileUtils writer)
	{
		if (skipTags != null && skipTags.length() > 0)
			_arrSkipTags = skipTags.split(",");
		_txtWriter = writer;
	}

	/**
	 * Creates a new visitor telling it the tags for which attributes can have unsafe EL.    
	 * @param skipTags an array of tag name 
	 */
	public NodeVisitor(String[] skipTags, TextFileUtils writer)
	{
		_arrSkipTags = skipTags;
		_txtWriter = writer;
	}

	/* (non-Javadoc)
	 * @see org.apache.jasper.compiler.Node.Visitor#visit(org.apache.jasper.compiler.Node.JspBody)
	 */
	@Override
	public void visit(JspBody n) throws JasperException
	{
		if (n.getBody() != null)
			n.getBody().visit(this);
	}

	/* (non-Javadoc)
	 * @see org.apache.jasper.compiler.Node.Visitor#visit(org.apache.jasper.compiler.Node.Expression)
	 */
	@Override
	public void visit(Expression n) throws JasperException
	{
		_txtWriter.write(n.getStart().getFile(), "SCRIPLET", n.getStart().getLineNumber(), "", "<%=".concat(n.getText()).concat("%>\n"));
	}

	/* (non-Javadoc)
	 * @see org.apache.jasper.compiler.Node.Visitor#visit(org.apache.jasper.compiler.Node.ELExpression)
	 */
	@Override
	public void visit(ELExpression n) throws JasperException
	{
		Node parent = null;
		String txt = null;

		parent = n.getParent();
		txt = n.getText();
		if (StringUtils.isEmpty(txt))
			_txtWriter.write(n.getStart().getFile(), "EMPTYEL", n.getStart().getLineNumber(), parent.getQName(), "");
		else if (!"c:out".equalsIgnoreCase(parent.getQName()) && !txt.startsWith("fn:escapeXml"))
		{
			_txtWriter.write(n.getStart().getFile(), "ELINHTML", n.getStart().getLineNumber(), parent.getQName(), 
								"${".concat(txt).concat("}\n"));
		}
	}

	/* (non-Javadoc)
	 * @see org.apache.jasper.compiler.Node.Visitor#visit(org.apache.jasper.compiler.Node.CustomTag)
	 */
	@Override
	public void visit(CustomTag n) throws JasperException
	{
		visitAttributes(n);
		if (n.getBody() != null)
			n.getBody().visit(this);
	}

	/* (non-Javadoc)
	 * @see org.apache.jasper.compiler.Node.Visitor#visit(org.apache.jasper.compiler.Node.UninterpretedTag)
	 */
	@Override
	public void visit(UninterpretedTag n) throws JasperException
	{
		visitAttributes(n);
		if (n.getBody() != null)
			n.getBody().visit(this);
	}

/*----------------------------------------------------------------------------------------------------------------------------------
 * HELPERS
 *--------------------------------------------------------------------------------------------------------------------------------*/
	/**
	 * Helper function to validate the attributes of custom JSP tag.
	 * @param n The custom tag
	 */
	private void visitAttributes(Node n)
	{
		String qName = null;
		String value = null;
		Attributes attrs = null;

		qName = n.getQName();
		if ("spring:message".equalsIgnoreCase(qName))
		{
			checkTextAttribute(qName, n);
			return;
		}

		if (skipTag(qName)) return;
		attrs = n.getAttributes();
		for (int i=0; i < attrs.getLength(); i++)
		{
			value = attrs.getValue(i);
			if (value.startsWith("${") && value.indexOf("escapeXml:") < 0)
				_txtWriter.write(n.getStart().getFile(), "UNSAFEEL", n.getStart().getLineNumber(), qName, 
								attrs.getQName(i).concat("=\"").concat(value).concat("\"\n"));
		}
	}

	/**
	 * Helper function to flag an error if text attribute is used on spring:message tag
	 * @param qName The XML qualified tag name.
	 * @param n The tag node
	 */
	private void checkTextAttribute(String qName, Node n)
	{
		Attributes attrs = null;

		attrs = n.getAttributes();
		for (int i=0; i < attrs.getLength(); i++)
		{
			if ("text".equals(attrs.getLocalName(i)))
			{
				_txtWriter.write(n.getStart().getFile(), "USEOFTEXT", n.getStart().getLineNumber(), qName, 
								attrs.getQName(i).concat("=\"").concat(attrs.getValue(i)).concat("\"\n"));
				break;
			}
		}
	}

	/**
	 * helper to check whether the tag should be checked or not. 
	 * @param qName The XML qualified tag name
	 * @return true if tag needs to be ignored
	 */
	private boolean skipTag(String qName)
	{
		boolean retVal = false;

		if (null == qName) return true;
		if (null == _arrSkipTags) return false;

		for (String tagName : _arrSkipTags)
		{
			if (tagName.equalsIgnoreCase(qName)) 
			{
				retVal = true;
				break;
			}
		}
		return retVal;
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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


Written By
Software Developer (Senior) Freelancer
India India
I am a software professional with over 20 years of commercial business applications design and development experience.

My programming experience includes Java, Spring, .NET, Classic VB & ASP, Scripting, Power Builder, PHP, Magic & far far ago FoxPro, C, Assembly and COBOL.

From last 11 years I am mostly working with Java Technology. I am currently available to take up new assignments.

Comments and Discussions