我在servlet中使用以下代码:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out=response.getWriter();
response.setContentType("text/html");
out.println("<html>");
out.println("<body>");
out.println("<script>alert(1)</script>");
out.println("</body>");
out.println("</html>");
}
和下面的过滤器代码:
public class SampleFilter implements Filter {
protected FilterConfig config;
public void init(FilterConfig config) throws ServletException {
this.config = config;
}
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
ServletResponse newResponse = response;
if (request instanceof HttpServletRequest) {
System.out.println("in filter if1");
newResponse = new CharResponseWrapper((HttpServletResponse) response);
}
System.out.println("after filter if1");
chain.doFilter(request, newResponse);
long elapsed = System.currentTimeMillis() - startTime;
if (newResponse instanceof CharResponseWrapper) {
System.out.println("in filter if2");
String text = newResponse.toString();
if (text != null) {
text = SampleFilter.HTMLEntityEncode(text);//.toUpperCase();
response.getWriter().write(text);
}
}
System.out.println("after filter if2");
config.getServletContext().log(" took " + elapsed + " ms");
System.out.println(elapsed);
}
private static String HTMLEntityEncode(String input) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < input.length(); i++) {
char ch = input.charAt(i);
if (Character.isLetterOrDigit(ch) || Character.isWhitespace(ch)) {
sb.append(ch);
} else {
sb.append("&#" + (int)ch + ";");
}
}
return sb.toString();
}
}
我想在浏览器中获得以下显示数据:
<script>alert(1)</script>
rather I am getting
<html>
<body>
<script>alert(1)</script>
</body>
</html>
别这么辛苦了。只需使用JSP生成HTML输出。JSP标准标记库(JSTL)提供了内置的方法,以<c:out>
标记和${fn:escapeXml()}
函数的形式将用户控制的数据从XSS攻击漏洞中逃脱。
<p>Welcome, <c:out value="${user.name}" />!</p>
...
<input type="text" name="foo" value="${fn:escapeXml(param.foo)}" />
它们将通过>
转义像<
这样的预定义XML实体,因此它变得完全无害。
servlet不是为生成HTML输出而设计的。它们被设计用于控制请求/响应。
参见:
- JSP/Servlet web应用程序中的XSS防范
当尝试防止XSS攻击时,您必须将有效代码与潜在的危险部分从有效表达式中分离出来。有不同的技术可以实现这一点:
转义绑定数据:在这种情况下,您必须使用某种模板技术。模板中定义的任何内容都被认为是安全的。在最简单的情况下,所有绑定的数据都被认为是危险的,因此被转义。一个简单的解决方案是Snippetory。(是的,我养成了这个习惯。你可以从Sourceforge或maven repo获得它)模板可能看起来像这样:
<html>
<body>
$attack
$text
</body>
</html>
那么绑定代码可能看起来像这样:
Template page = Syntaxes.FLUYT_X.readResource("template.html")
.encoding(Encodings.html);
page.set("attack", "<script>alert(0)</script>");
page.set("text", "text <--> escaping");
page.render(response.getWriter());
然而,缺点是整个输出处理必须以正确的方式完成。但我认为对于严肃的项目来说,这是最重要的方式。
现在一些方法可以在处理之后使用,但是通常是与转义绑定数据结合使用来实现复杂的事情,比如在Stackoverflow上的编辑器字段:
白清单:本质上,您分析数据(可能使用html解析器)并转义不属于白清单上标记的所有内容。删除所有你不允许的属性。这是相当安全的,但也有很大的限制。此外,它非常复杂,所以我不能在这里提供一个例子。
黑名单:几乎一样,只是你让你的黑名单上没有的东西通过。如果你忘记了什么危险的攻击仍然是可能的。
在您的情况下,使用填充是不可能的,因为没有办法将合法内容与任何已注入的内容分开。针对XSS的启发式黑盒防御可以通过过滤输入而不是输出来应用。
我已经为Jersey REST API实现了一个XSS过滤器。可以很容易地提取代码并将其应用于标准Java Filter。
大多数人建议对输出进行编码,但是由于我们的数据可以通过JavaScript API访问,并且无法保证我们的客户会过滤掉XSS漏洞,因此我们选择在输入时过滤掉XSS漏洞。这种方法的另一个好处是,过滤只进行一次,而不是每次输出数据时都进行过滤。
注意,过滤器需要与JSR 303的@SafeHtml注释一起使用,以确保正确过滤POST数据的内容。
我在我的博客上记录了这一点:http://codehustler.org/blog/jersey-cross-site-scripting-xss-filter-for-java-web-apps/