I've added a filter below that works with Jersey 2.x. However, it doesn't perform the XSS fixing for Cookies as I haven't found a way to modify those.
Important to note that this needs to be used in combination with @SafeHtml on POJO properties in order to clean up those values.
@PreMatching
public class XSSFilter implements ContainerRequestFilter
{
/**
* @see ContainerRequestFilter#filter(ContainerRequest)
*/
@Override
public void filter( ContainerRequestContext request )
{
cleanQueryParams( request );
cleanHeaders( request.getHeaders() );
}
/**
* Replace the existing query parameters with ones stripped of XSS vulnerabilities
* @param request
*/
private void cleanQueryParams( ContainerRequestContext request )
{
UriBuilder builder = request.getUriInfo().getRequestUriBuilder();
MultivaluedMap<String, String> queries = request.getUriInfo().getQueryParameters();
for( Map.Entry<String, List<String>> query : queries.entrySet() )
{
String key = query.getKey();
List<String> values = query.getValue();
builder.replaceQueryParam( key );
for( String value : values ) {
builder.replaceQueryParam( key, Utils.stripXSS( value ) );
}
}
request.setRequestUri( builder.build() );
}
/**
* Replace the existing headers with ones stripped of XSS vulnerabilities
* @param headers
*/
private void cleanHeaders( MultivaluedMap<String, String> headers )
{
for( Map.Entry<String, List<String>> header : headers.entrySet() )
{
String key = header.getKey();
List<String> values = header.getValue();
List<String> cleanValues = new ArrayList<String>();
for( String value : values ) {
cleanValues.add( Utils.stripXSS( value ) );
}
headers.put( key, cleanValues );
}
}
}
The stripXSS functions are the following:
/**
* Strips any potential XSS threats out of the value
*
* @param value
* @return
*/
public static String stripXSS( String value )
{
return stripXSS( value, Whitelist.none() );
}
/**
* Strips any potential XSS threats out of the value excluding
* the white listed HTML
*
* @param value
* @param whitelist
* @return
*/
public static String stripXSS( String value, Whitelist whitelist )
{
if( StringUtils.isBlank( value ) )
return value;
// Use the ESAPI library to avoid encoded attacks.
value = ESAPI.encoder().canonicalize( value );
// Avoid null characters
value = value.replaceAll("\0", "");
// Clean out HTML
Document.OutputSettings outputSettings = new Document.OutputSettings();
outputSettings.escapeMode( EscapeMode.xhtml );
outputSettings.prettyPrint( false );
value = Jsoup.clean( value, "", whitelist, outputSettings );
return value;
}
Also updated the original post: http://codehustler.org/blog/jersey-cross-site-scripting-xss-filter-for-java-web-apps/