Skip to content

Instantly share code, notes, and snippets.

@barrypitman
Last active October 19, 2016 21:24
Show Gist options
  • Save barrypitman/4557334 to your computer and use it in GitHub Desktop.
Save barrypitman/4557334 to your computer and use it in GitHub Desktop.
/**
* Servlet filter that checks all request parameters for potential XSS attacks.
* see http://bazageous.com/2011/04/14/preventing-xss-attacks-with-antisamy/
*
* @author barry pitman
* @since 2011/04/12 5:13 PM
*/
public class AntiSamyFilter implements Filter {
private static final Logger LOG = Logger.getLogger(AntiSamyFilter.class);
/**
* AntiSamy is unfortunately not immutable, but is threadsafe if we only call
* {@link AntiSamy#scan(String taintedHTML, int scanType)}
*/
private final AntiSamy antiSamy;
public AntiSamyFilter() {
try {
URL url = this.getClass().getClassLoader().getResource("antisamy-slashdot-1.4.4.xml");
Policy policy = Policy.getInstance(url.getFile());
antiSamy = new AntiSamy(policy);
} catch (PolicyException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (request instanceof HttpServletRequest) {
CleanServletRequest cleanRequest = new CleanServletRequest((HttpServletRequest) request, antiSamy);
chain.doFilter(cleanRequest, response);
} else {
chain.doFilter(request, response);
}
}
public void init(FilterConfig filterConfig) throws ServletException {
}
public void destroy() {
}
/**
* Wrapper for a {@link HttpServletRequest} that returns 'safe' parameter values by
* passing the raw request parameters through the anti-samy filter. Should be private
*/
private static class CleanServletRequest extends HttpServletRequestWrapper {
private final AntiSamy antiSamy;
private CleanServletRequest(HttpServletRequest request, AntiSamy antiSamy) {
super(request);
this.antiSamy = antiSamy;
}
/**
* overriding getParameter functions in {@link ServletRequestWrapper}
*/
@Override
public String[] getParameterValues(String name) {
String[] originalValues = super.getParameterValues(name);
if (originalValues == null) {
return null;
}
List<String> newValues = new ArrayList<String>(originalValues.length);
for (String value : originalValues) {
newValues.add(filterString(value));
}
return newValues.toArray(new String[newValues.size()]);
}
@Override
@SuppressWarnings("unchecked")
public Map getParameterMap() {
Map<String, String[]> originalMap = super.getParameterMap();
Map<String, String[]> filteredMap = new ConcurrentHashMap<String, String[]>(originalMap.size());
for (String name : originalMap.keySet()) {
filteredMap.put(name, getParameterValues(name));
}
return Collections.unmodifiableMap(filteredMap);
}
@Override
public String getParameter(String name) {
String potentiallyDirtyParameter = super.getParameter(name);
return filterString(potentiallyDirtyParameter);
}
/**
* @param potentiallyDirtyParameter string to be cleaned
* @return a clean version of the same string
*/
private String filterString(String potentiallyDirtyParameter) {
if (potentiallyDirtyParameter == null || "".equals(potentiallyDirtyParameter)) {
return potentiallyDirtyParameter;
}
try {
CleanResults cr = antiSamy.scan(potentiallyDirtyParameter, AntiSamy.DOM);
if (cr.getNumberOfErrors() > 0) {
LOG.warn("antisamy encountered problem with input: " + cr.getErrorMessages());
}
return cr.getCleanHTML();
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
}
}
@armalhotra
Copy link

Hi Barry, Is this filtering the request parameters only or also the request body for possible stored XSS ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment