如何使用过滤器执行输出编码以防止 XSS?
Posted
技术标签:
【中文标题】如何使用过滤器执行输出编码以防止 XSS?【英文标题】:How to perform output encoding using filter to prevent XSS? 【发布时间】:2013-03-19 20:49:11 【问题描述】:我在 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>
我得到了
<html>
<body>
<script>alert(1)</script>
</body>
</html>
在浏览器中。
任何帮助都会很棒。
【问题讨论】:
【参考方案1】:不要硬着头皮做。只需使用 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)" />
他们会像 <
by &gt;
一样逃离 predefinied XML entities,这样它就变得完全无害了。
Servlets 不是为生成 HTML 输出而设计的。它们旨在控制请求/响应。
另见:
XSS prevention in JSP/Servlet web application【讨论】:
我想知道是否有任何方法可以在不修改 JSP 的情况下执行输出编码,因为客户端告诉我们使用过滤器。【参考方案2】:在尝试防止 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());
但是,缺点是整个输出处理必须以正确的方式完成。但我认为对于严肃的项目,这是最重要的方式。
现在有些方法可以在处理后使用,但通常与绑定数据的转义结合使用,以在 *** 上实现诸如编辑器字段之类的复杂事物:
白名单:本质上,您分析数据(可能使用 html 解析器)并转义所有不属于您放在白名单上的标签的内容。并删除您不允许的所有属性。这非常安全,但也非常严格。另外它很复杂,所以我不能在这里提供一个例子。
黑名单:几乎相同,只是你让不在你的 vlack 名单上的东西。如果你忘记了一些危险的攻击仍然可能。
【讨论】:
【参考方案3】:在您的情况下,使用填充是不可能的,因为它无法将合法内容与任何已注入的内容分开。可以通过过滤输入而不是输出来应用针对 xss 的启发式黑盒防御。
【讨论】:
我们可以使用过滤器来执行一般的输出编码,而不考虑我的代码吗? 编码?是的。黑匣子安全?没有。 但是由于没有办法将合法内容与任何注入的内容分开,那么编码将如何取得成果。 我没有说任何特定的水果。我不知道你需要什么水果。没有什么可以阻止您以任何您想要的方式对输出进行编码(base64、rot13、utf16,将所有“a”更改为“@”等),但是,正如我所说,您不会以这种方式获得任何 XSS 保护.【参考方案4】:我为 Jersey REST API 实现了 XSS 过滤器。可以轻松提取代码并将其应用于标准 Java 过滤器。
大多数人建议对输出进行编码,但由于我们的数据可以通过 javascript API 访问,并且无法保证我们的客户会过滤掉 XSS 漏洞,所以我们选择过滤掉输入中的 XSS 漏洞。这种方法的另一个好处是过滤只进行一次,而不是每次输出数据。
注意过滤器需要与JSR 303的@SafeHtml注解配合使用,以保证POST数据的内容被正确过滤。
我已经在我的博客上记录了这一点:http://codehustler.org/blog/jersey-cross-site-scripting-xss-filter-for-java-web-apps/
【讨论】:
以上是关于如何使用过滤器执行输出编码以防止 XSS?的主要内容,如果未能解决你的问题,请参考以下文章