如何使用过滤器执行输出编码以防止 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) 提供了内置的方法来将用户控制的数据从 &lt;c:out&gt; 标签和 $fn:escapeXml() 函数风格的 XSS 攻击漏洞中逃脱。..

<p>Welcome, <c:out value="$user.name" />!</p>
...
<input type="text" name="foo" value="$fn:escapeXml(param.foo)" />

他们会像 &lt; by &amp;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?的主要内容,如果未能解决你的问题,请参考以下文章

asp网站如何防止XSS攻击

如何防止跨站点脚本攻击

利用微软AntiXss Library过滤输出字符,防止XSS攻击

如何在 laravel 视图的输出上应用 xss 过滤器?

如何在 django 中防止 XSS 攻击

XSS防御速查表