I found the next code that prevent xss atacks. But it has a problem. It works fine with forms that have enctype="application/x-www-form-urlencoded", but not with forms that have enctype="multipart/form-data". I observe that getParameterValues() and rest of methods are not called.
//— XSS Filter —//
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
/**
* Servlet Filter implementation class XSSFilter
*/
public class XSSFilter implements Filter {
@SuppressWarnings("unused")
private FilterConfig filterConfig;
/**
* Default constructor.
*/
public XSSFilter() {
}
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
public void destroy() {
this.filterConfig = null;
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(new RequestWrapperXSS((HttpServletRequest) request), response);
}
}
//— RequestWrapperXSS —//
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public final class RequestWrapperXSS extends HttpServletRequestWrapper {
public RequestWrapperXSS(HttpServletRequest servletRequest) {
super(servletRequest);
}
public String[] getParameterValues(String parameter) {
System.out.println("entra parameterValues");
String[] values = super.getParameterValues(parameter);
if (values == null) {
return null;
}
int count = values.length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = cleanXSS(values[i]);
}
return encodedValues;
}
public String getParameter(String parameter) {
System.out.println("entra getParameter");
String value = super.getParameter(parameter);
if (value == null) {
return null;
}
return cleanXSS(value);
}
public String getHeader(String name) {
System.out.println("entra header");
String value = super.getHeader(name);
if (value == null)
return null;
return cleanXSS(value);
}
private String cleanXSS(String cadena) {
System.out.println("entra claean XSS");
StringBuffer sb = new StringBuffer(cadena.length());
// true if last char was blank
boolean lastWasBlankChar = false;
int len = cadena.length();
char c;
for (int i = 0; i < len; i++)
{
c = cadena.charAt(i);
if (c == ' ') {
// blank gets extra work,
// this solves the problem you get if you replace all
// blanks with , if you do that you loss
// word breaking
if (lastWasBlankChar) {
lastWasBlankChar = false;
sb.append(" ");
}
else {
lastWasBlankChar = true;
sb.append(' ');
}
}
else {
lastWasBlankChar = false;
//
// HTML Special Chars
if (c == '"')
sb.append(""");
else if (c == '&')
sb.append("&");
else if (c == '<')
sb.append("<");
else if (c == '>')
sb.append(">");
else if (c == '\n')
// Handle Newline
sb.append("<br/>");
else {
int ci = 0xffff & c;
if (ci < 160 )
// nothing special only 7 Bit
sb.append(c);
else {
// Not 7 Bit use the unicode system
sb.append("&#");
sb.append(new Integer(ci).toString());
sb.append(';');
}
}
}
}
return sb.toString();
}
}
In case of
multipart/form-datarequests, the data is available bygetPart()andgetParts()methods, not bygetParameter(),getParameterValues()and consorts.Note that those methods are introduced in Servlet 3.0 and that in older versions there is not any standard API facility to extract data from
multipart/form-datarequests. The defacto API which is been used for that instead is the well known Apache Commons FileUpload.Unrelated to the concrete problem, this is IMO a bad way to prevent XSS. XSS should be prevented in the view side during redisplaying the user-controlled input, right there where it can harm. Escaping before processing the user-controlled input will only risk in double escaping because it’s not the "standard" way of XSS prevention. The developers should just ensure that they always escape user-controlled data in the view side using JSTL
<c:out>orfn:escapeXml()or any other MVC framework supplied facilities (JSF for example escapes everything by default).See also