An example of a flawed XSS BlackList filter
Here is my response to http://myappsecurity.blogspot.com/2007/01/xss-filter-to-protect-from-xss-attacks.html
This is a good but dangerous effort, the problem is in this example is that Anurag is applying a blackList filter and is only protecting against one case of xss.
Here is the original code code:
String html = request.getParameter(”html”);
out.println(”Here is the filtered output of the html you submitted.”);
out.println(filterRequest(html));
And if I change it to:
String html = “<a href=’” + filterRequest(request.getParameter(”url”)) + “‘>XSS link</a>”;
out.println(”Here is the filtered output of the html you submitted.”);
out.println(html);
which is another example of using user input to create a link
the filter can be easily bypassed.
1) normal request: http://127.0.0.1:8080/servlets-examples/servlet/XSSFilter?url=nextServlet
2) already a type of XSS since this type of redirection should not be allowed: http://127.0.0.1:8080/servlets-examples/servlet/XSSFilter?url=http://www.google.com
3) and here is an XSS 101 payload: http://127.0.0.1:8080/servlets-examples/servlet/XSSFilter?url=nextPage’ onmouseover=’Javascript:alert(document.cookie)
4) or if you want to make sure the user cannot escape: http://127.0.0.1:8080/servlets-examples/servlet/XSSFilter?url=http://www.google.com’ onmouseover=’Javascript:alert(document.cookie)” style=’display:block;position:absolute;left:0;right:0;width:100%25;height:100%25 (thx pdp)
5) note that in example 4) above I could had used ” in the payload since your filter will convert ” to ‘ : http://127.0.0.1:8080/servlets-examples/servlet/XSSFilter?url=nextPage” onmouseover=”Javascript:alert(document.cookie)
6) of course that in this case you could always just do: http://127.0.0.1:8080/servlets-examples/servlet/XSSFilter?url=javascript:alert(document.cookie)
7) and even if you added ‘ to the filter (which might be a problem since in some case you will need to accept it), it wouldn’t cover for this case: String html = “<a href=” + filterRequest(request.getParameter(”url”)) + “>XSS link</a>”;
and lets not forget the XSS caused by double encoding or double decoding in the code
I hope this shows how hard it is to properly mitigate against XSS and that in most cases white listing is the only safe option (and even in those cases XSS might occur).
Another solution that is very rarely talked is to by default encode EVERYthing sent to out.println and force the developers to use strong-typed html classes to create HTML tags.
In the above example your would change
String html = “<a href=’” + filterRequest(request.getParameter(”url”)) + “‘>XSS link</a>”;
out.println(html);
for
safeHtmlBuilder.a html = safeHtmlBuilder.a(request.getParameter(”html”), “XSS link”)
safeHtml.out(html);
Assuming of course that safeHtmlBuilder.a(…) was built properly
Even better than encoding out.println would be to block the developer from invoking out.println directly (which could be enforced via (’Shock Horror!!!’) the Java security manager (or in Partial Trust in .Net)).
We would have a nice solution for XSS (and this is a good example of what I was talking about a while back on using Sandboxes to create environments where these types of vulnerabilities are very hard to exists)
Here is the Code used in my tests
Compiled with
XSS_Test>”%JAVA_HOME%\bin\javac” -classpath “.;..\..\..\..\common\lib\servlet-api.jar” XSSFilter.java
import java.io.*;
import java.net.*;
import javax.servlet.*;
import javax.servlet.http.*;
/**
*
* @author anurag agarwal (modified by Dinis Cruz for this blog)
* @version 1.1
*/
public class XSSFilter extends HttpServlet {
private String[] filterChars = {”<”, “>”, “<”, “>”, “&#”, “\”", “\\”, “0x”};
private String[] replacementChars = {” “, ” “, ” “, ” “, “#”, “‘”, “/”, “0 x”};
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType(”text/html;charset=UTF-8″);
PrintWriter out = response.getWriter();
String html = “<a href=’” + filterRequest(request.getParameter(”url”)) + “‘>XSS link</a>”;
out.println(”Here is the filtered output of the html you submitted.”);
out.println(html);
out.close();
}
private String filterRequest(String param) {
String value = param;
if( param!=null) {
for(int i = 0; i < filterChars.length; i++) {
value = filterCharacters(filterChars[i], replacementChars[i], value);
}
}
return value;
}
private String filterCharacters(String originalChar, String newChar, String param)
{
StringBuffer sb = new StringBuffer(param);
for(int position = param.toLowerCase().indexOf(originalChar); position >= 0; ) {
sb.replace(position, position + originalChar.length(), newChar);
param = sb.toString();
position = param.toLowerCase().indexOf(originalChar);
}
return sb.toString();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
}

January 23rd, 2007 at 10:15 am
The main point is that XSS is an attack vector that is very hard to mitigate. Why? Well, different applications have different requirements that involve different problems. Some problems can be grouped and solved with a single solution. Others can’t! You need to write custom solutions.
Also, be aware that currently developed XSS filters protect the client by sanitizing the input sent to the server. That’s very good, however, I’ve seen many applications that do pretty good job on the server side but they fail to perform that well on the client side. I am talking about DOM based XSS. If your JavaScript code makes use of cookies, queries, fragment identifiers or other type of input without sanitizing it, attackers can abuse it in order to execute malicious code on the browser.
January 23rd, 2007 at 1:58 pm
dinis
What you mentioned is correct but if i am correct then the situation you mentioned is for the sites which wants you to input html tags like blogs, or certain discussion forums, etc.
This approach is definitely not right for those websites.
I agree that this approach does not covers all the websites, but then in my opinion 5-10% of the websites would require such data and even those sites would not require these characters in all of the input. Most of the websites in their regular functionality would not even need the filtered characters mentioned here as input.
- Anurag