Tuesday, January 23, 2007

XSS filter to protect from XSS attacks

Here are the excerpts from the chilling effect

Grossman, who founded his own research company, WhiteHat, claims XSS vulnerabilities can be found in 70 percent of websites. RSnake goes further. "I know Jeremiah says seven of 10. I'd say there's only one in 30 I come across where the XSS isn't totally obvious. I don't know of a company I couldn't break into [using XSS]."
If you apply Grossman's number to a recent Netcraft survey, which estimated that there are close to 100 million websites, you've got 70 million sites with XSS vulnerabilities. Repairing them one-off, two-off, 200,000-off is spitting in the proverbial ocean. Even if you've disclosed, you've done very little to reduce the overall risk of exploit. "Logistically, there's no way to disclose this stuff to all the interested parties," Grossman says. "I used to think it was my moral professional duty to report every vulnerability, but it would take up my whole day."


If we can put an XSS filter in the framework (for example, as a servlet filter in the Java EE) then it would make it a lot easier for the developers to not worry about all the places where they are accepting the input from the client browser. Instead they can just do a request.getParameter() and the servlet filter would do all the filtering for XSS characters with each and every request which comes in to the JSP pages or servlets.

I have created a xss filter which can be tested at http://www.attacklabs.com/xssfilter/. It filters only 8 characters but it protects from all the possible attack strings mentioned in the Rsnake’s cheat sheet. If you can find an xss attack which can bypass the filter, then please do submit it here or email it to me at anurag.agarwal@yahoo.com

Please bear in mind that this filter is not the right choice if you want your users to input HTML tags or urls.

Source Code

import java.io.*;
import java.net.*;

import javax.servlet.*;
import javax.servlet.http.*;

/**
*
* @author anurag agarwal
* @version 1.0
*/
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 = request.getParameter("html");
out.println("Here is the filtered output of the html you submitted.");

out.println(filterRequest(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);
}
}

6 comments:

Anonymous said...

Hi,
nice but you forgot something very important:
What if we have for example a blogging webapplication in which an admin should be able to write postings with the use of HTML but the readers which want to leave a comment shouldn't be able to do so. Here you need to have a regulation about the filter rules for each group of users and so, it's not that easy to have one filter for everyone and everywhere. Especially you have problems, when you want or have to allow some HTML-Tags to everyone, then you filter will not be able to work any more in the way our application should.
So I think once more this is a proof that we can filter (all known) XSS-Attacks very easy but only if we reduce the functionality of our application to a minimum.

Anonymous said...

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.

see http://blogs.owasp.org/diniscruz/2007/01/23/an-example-of-a-flawed-xss-blacklist-filter/ for more details

Dinis Cruz

Anurag Agarwal said...

I agree that it does not covers all the websites. For examples blogs which lets you enter certain html characters or the mathematics site as you mentioned, but then in my opinion 5-10% of the websites would require such data and even those sites would not require in all of the input. Most of the websites in their regular functionality would not even need the filtered characters here as input.

This module here does not cater to those applications.

Anonymous said...

Hi Anurag,

Your filter seems to replace "&#" to "#",
but "&\0#" is NOT replaced to "#" (\0 = NUL character).
As you know, IE ignores NUL, so "&\0#" is treated as "&#".

Of course, this does'nt mean that your filter has exploitable
XSS hole, but I think this represents potential dangerousness of
your approach.

By the way, I could not understand why "&#" should be replaced.
I think just escaping "&" to "&" is the correct and easy way
in many situations. < > " ' are the same.

In addition, you have better remove non-SGML chars (ex. NUL),
because they should not appear in html and they make filtering
so difficult.

--
teracc

Anurag Agarwal said...

teracc

thanks for pointing this out. In this PoC, i am replacing \ with / but there is something else i was working on and there it would have slipped through the cracks. I appreciate your input.

anurag

Anonymous said...

Thanks for sharing the filter!