Dashboard > Stripes > ... > User Additions > XSS filter
Stripes Log In   View a printable version of the current page.
XSS filter
Added by Jeff Ferber, last edited by Jeff Ferber on Jul 10, 2007  (view change)

Stripes has moved! This site is no longer being actively maintained. Please point your browsers at http://www.stripesframework.org and update your bookmarks. Thank you.

I tested the code below against all of the known xss attacks that are listed on http://ha.ckers.org/xss.html as of July 2007, except for one. I haven't yet tested it against the 'US-ASCII encoding' attack (which tomcat is vulnerable)

The wrapper escapes all params that Stripes binds during its Validation & Binding phase.  Parameters that you get manually through request.getParameter() are NOT sanitized. The code below basically follows the xss security guidance posted at http://www.owasp.org.

add to web.xml. for example:
<init-param>
	<param-name>Interceptor.Classes</param-name>
	<param-value>
		com.mypath.web.security.XssInterceptor
		net.sourceforge.stripes.controller.BeforeAfterMethodInterceptor
	</param-value>
</init-param>
XssInterceptor.java
package com.mypath.web.security;

import javax.servlet.http.HttpServletRequest;

import net.sourceforge.stripes.action.Resolution;
import net.sourceforge.stripes.controller.ExecutionContext;
import net.sourceforge.stripes.controller.Interceptor;
import net.sourceforge.stripes.controller.Intercepts;
import net.sourceforge.stripes.controller.LifecycleStage;
import net.sourceforge.stripes.controller.StripesRequestWrapper;

@Intercepts(LifecycleStage.BindingAndValidation)
public class XssInterceptor implements Interceptor
{
	private static ThreadLocal<ExecutionContext> currentContext = new ThreadLocal<ExecutionContext>();
	
	public Resolution intercept(ExecutionContext context) throws Exception 
	{
        StripesRequestWrapper stripesWrapper = null;
        HttpServletRequest originalRequest = null;
        try {
            currentContext.set(context);
            stripesWrapper = StripesRequestWrapper.findStripesWrapper(context
                    .getActionBeanContext().getRequest());
            originalRequest = (HttpServletRequest) stripesWrapper.getRequest();
            stripesWrapper.setRequest(new XssRequestWrapper(originalRequest));
            return context.proceed();
        } finally {
            currentContext.remove();
            if (stripesWrapper != null && originalRequest != null)
                stripesWrapper.setRequest(originalRequest);
        }
    }
}
XssRequestWrapper.java
package com.mypath.web.security;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.apache.log4j.Logger;

public class XssRequestWrapper extends HttpServletRequestWrapper
{
	private static final Logger logger = Logger.getLogger(XssRequestWrapper.class);


	private Map<String, String[]> sanitized;
	private Map<String, String[]> orig;
	
	@SuppressWarnings("unchecked")
	public XssRequestWrapper(HttpServletRequest req) 
	{
		super(req);
		orig = req.getParameterMap();	
		sanitized = getParameterMap();
		if (logger.isDebugEnabled())
			snzLogger();
	}		

	@Override
	public String getParameter(String name) 
	{		
		String[] vals = getParameterMap().get(name); 
		if (vals != null && vals.length > 0) 
			return vals[0];
		else        
			return null;        
	}


	@SuppressWarnings("unchecked")
	@Override
	public Map<String, String[]> getParameterMap() 
	{	
		if (sanitized==null)
			sanitized = sanitizeParamMap(orig);
		return sanitized;			

	}

	@Override
	public String[] getParameterValues(String name)
	{	
		return getParameterMap().get(name);
	}


	private  Map<String, String[]> sanitizeParamMap(Map<String, String[]> raw) 
	{		
		Map<String, String[]> res = new HashMap<String, String[]>();
		if (raw==null)
			return res;
	
		for (String key : (Set<String>) raw.keySet())
		{			
			String[] rawVals = raw.get(key);
			String[] snzVals = new String[rawVals.length];
			for (int i=0; i < rawVals.length; i++) 
			{
				snzVals[i] = SafeHtmlUtil.sanitize(rawVals[i]);
			}
			res.put(key, snzVals);
		}			
		return res;
	}


	@SuppressWarnings("unchecked")
	private void snzLogger()
	{
		for (String key : (Set<String>) orig.keySet())
		{
			String[] rawVals = orig.get(key);
			String[] snzVals = sanitized.get(key);
			if (rawVals !=null && rawVals.length>0)
			{
				for (int i=0; i < rawVals.length; i++) 
				{
					if (rawVals[i].equals(snzVals[i]))															
						logger.debug("Sanitization. Param seems safe: " + key + "[" + i + "]=" + snzVals[i]);				
					else
						logger.debug("Sanitization. Param modified: " + key + "[" + i + "]=" + snzVals[i]);
				}		
			}
		}
	}

	// TODO  need to sanitize getHeader(), getCookie(), etc ??

}
SafeHtmlUtil.java (barebones version)
public class SafeHtmlUtil
{
	public static String sanitize(String raw)
	{
		if (raw==null || raw.length()==0)
			return raw;

		return HTMLEntityEncode(canonicalize(raw));
	}


	private static Pattern scriptPattern = new Pattern("script", REFlags.IGNORE_CASE);
	private static Replacer scriptReplacer = scriptPattern.replacer("&#x73;cript");

	public static String HTMLEntityEncode(String input)
	{
		String next = scriptReplacer.replace(input);

		StringBuffer sb = new StringBuffer();
		for ( int i = 0; i < next.length(); ++i )
		{
			char ch = next.charAt( i );

			if (ch=='<')
				sb.append("&lt;");
			else if (ch=='>')
				sb.append("&gt;");
			else
				sb.append(ch);
		}

		return sb.toString();
	}


	// "Simplifies input to its simplest form to make encoding tricks more difficult"
	// though it didn't do seem to do anything to hex or html encoded characters... *shrug* maybe for unicode?
	public static String canonicalize( String input )
	{
		String canonical = sun.text.Normalizer.normalize( input, Normalizer.DECOMP, 0 );
		return canonical;
	}

Site powered by a free Open Source Project / Non-profit License (more) of Confluence - the Enterprise wiki.
Learn more or evaluate Confluence for your organisation.
Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.2.7 Build:#524 Jul 28, 2006) - Bug/feature request - Contact Administrators