XSS防御-使用AntiSamy

来源:互联网 发布:新概念英语网络课程 编辑:程序博客网 时间:2024/05/20 15:11

AntiSamy是OWASP的一个开源项目,通过对用户输入的 HTML / CSS / JavaScript 等内容进行检验和清理,确保输入符合应用规范。AntiSamy被广泛应用于Web服务对存储型和反射型XSS的防御中。

1、maven依赖

AntiSamy直接导入到工程即可,但是其运行依赖xercesImpl、batik、nekohtml,这些依赖默认会一起导入

<!-- OWASP AntiSamy --><dependency>  <groupId>org.owasp.antisamy</groupId>  <artifactId>antisamy</artifactId>  <version>1.5.5</version></dependency>

2、策略文件

AntiSamy对“恶意代码”的过滤依赖于策略文件。策略文件规定了AntiSamy对各个标签、属性的处理方法,策略文件定义的严格与否,决定了AntiSamy对XSS漏洞的防御效果。

在AntiSamy的jar包中,包含了几个常用的策略文件

这里写图片描述

我们可以自定义策略文件来过滤用户输入,但更多的会是基于现有的策略文件进行稍微的调整,以使其更贴合项目的实际需求。
这里写图片描述

要描述某种特定规则,XML无疑是个不错的选择,而AntiSamy策略文件也正是采用了XML格式。如图所示,除去文件头的AntiSamy策略文件可以分为八个部分

1)、directives

全局配置,对AntiSamy的过滤验证规则、输入及输出的格式进行全局性的控制

<directives>  <directive name="omitXmlDeclaration" value="true"/>  <directive name="omitDoctypeDeclaration" value="true"/>  <directive name="maxInputSize" value="200000"/>  <directive name="useXHTML" value="true"/>  <directive name="formatOutput" value="true"/>  <directive name="nofollowAnchors" value="true" />  <directive name="validateParamAsEmbed" value="true" />  <!--  remember, this won't work for relative URIs - AntiSamy doesn't  know anything about the URL or your web structure  -->  <directive name="embedStyleSheets" value="false"/>   <directive name="connectionTimeout" value="5000"/>  <directive name="maxStyleSheetImports" value="3"/></directives>

2)、common-regexps

公用正则表达式,需要使用正则的时候可以通过name直接引用

<common-regexps>  <regexp name="numberOrPercent" value="(\d)+(%{0,1})"/>  <regexp name="paragraph" value="([\p{L}\p{N},'\.\s\-_\(\)\?]|&amp;[0-9]{2};)*"/>    <regexp name="htmlId" value="[a-zA-Z0-9\:\-_\.]+"/></common-regexps>

假设后文需要使用”htmlId”这一正则时,直接根据对应的name属性进行引用即可

<!-- Common to all HTML tags  --><attribute name="id" description="The 'id' of any HTML attribute should not contain anything besides letters and numbers">    <regexp-list>        <!-- 直接根据正则的名称进行引用 -->        <regexp name="htmlId"/>    </regexp-list></attribute>

3)、common-attributes

通用的属性需要满足的输入规则,其中包括了标签和css的属性;在tag和css的处理规则中会引用到这些属性

<common-attributes>  <attribute name="classid">    <regexp-list>        <regexp name="anything" />    </regexp-list>  </attribute>  <attribute name="autocomplete">    <literal-list>      <literal value="on"/>      <literal value="off"/>    </literal-list>  </attribute></common-attributes>

4)、global-tag-attributes

所有标签的默认属性需要遵守的规则

<global-tag-attributes>    <!-- Not valid in base, head, html, meta, param, script, style, and title elements. -->    <attribute name="id"/>    <attribute name="style"/>    <attribute name="title"/>    <attribute name="class"/>    <!-- Not valid in base, br, frame, frameset, hr, iframe, param, and script elements.  -->    <attribute name="lang"/></global-tag-attributes>

5)、tags-to-encode

需要进行编码处理的标签

<tags-to-encode>  <tag>g</tag>  <tag>grin</tag></tags-to-encode>

6)、tag-rules

tag的处理规则,共有三种处理方式

  • remove

    对应的标签直接删除,如script标签处理规则为删除

    <tag name="script" action="remove"/>
  • truncate

    对应的标签进行缩短处理,直接删除所有属性,只保留标签和值

    如标题只保留标签和值

    <tag name="title" action="truncate"/>
  • validate

    对应的标签的属性进行验证,如果tag中定义了属性的验证规则,按照tag中的规则执行;如果标签中未定义属性,则按照 <global-tag-attributes> 中定义的处理

    <tag name="head" action="validate"/>

7)、css-rules

CSS的处理规则

<css-rules>  <property name="bottom" default="auto" description="">    <category-list>        <category value="visual"/>    </category-list>    <literal-list>        <literal value="auto"/>        <literal value="inherit"/>    </literal-list>    <regexp-list>        <regexp name="length"/>        <regexp name="percentage"/>    </regexp-list>  </property>  <property name="color" description="">    <category-list>        <category value="visual"/>    </category-list>    <literal-list>        <literal value="inherit"/>    </literal-list>    <regexp-list>        <regexp name="colorName"/>        <regexp name="colorCode"/>        <regexp name="rgbCode"/>        <regexp name="systemColor"/>    </regexp-list>  </property></css-rules>

8)、allowed-empty-tags

允许没有内容的标签

<allowed-empty-tags>  <literal-list>    <literal value="br"/>    <literal value="hr"/>    <literal value="a"/>    <literal value="img"/>    <literal value="link"/>    <literal value="iframe"/>    <literal value="script"/>    <literal value="object"/>    <literal value="applet"/>    <literal value="frame"/>    <literal value="base"/>    <literal value="param"/>    <literal value="meta"/>    <literal value="input"/>    <literal value="textarea"/>    <literal value="embed"/>    <literal value="basefont"/>    <literal value="col"/>    <literal value="div"/>  </literal-list></allowed-empty-tags>

大概清楚了每个标签代表的意义,便能够很容易地写出符合自己需求的策略文件了。我们再来简单的看下jar包中几个常见策略文件

  • antisamy-anythinggoes.xml

    允许所有有效的HTML和CSS元素输入(但能拒绝JavaScript或跟CSS相关的网络钓鱼攻击),因为它包含了对于每个元素的基本规则,所以你在裁剪其它策略文件的时候可以把它作为一个知识库,一般不建议使用。

  • antisamy-ebay.xml

    eBay 是当下最流行的在线拍卖网站之一。它是一个面向公众的站点,因此它允许任何人发布一系列富HTML的内容,允许输入的内容列表包含了比 Slashdot 更多的富文本内容,所以它的受攻击面也要大得多。

    该策略相对安全,适用于电子商务网站。

  • antisamy-myspace.xml

    MySpace 是最流行的一个社交网站之一。用户允许提交除了JavaScript之外的几乎所有他们想用的HTML和CSS。
    MySpace现在用一个黑名单来验证用户输入的HTML,相对较危险,不建议使用。

  • antisamy-slashdot.xml

    Slashdot 是一个提供技术新闻的网站,其安全策略非常严格。用户只能提交下列的HTML标签:<b>、<u>、<i>、<a>、<blockquote>,并且还不支持CSS。

    该策略文件来实现了类似的功能,允许所有文本格式的标签来直接修饰字体、颜色或者强调作用,适用于新闻网站的评论过滤。

  • antisamy-tinymce.xml

    只允许文本格式通过,相对较安全

  • antisamy.xml

    默认规则,允许大部分HTML通过

3、使用

其实 AntiSamy 在使用上是十分简单的,指定策略文件后构建AntiSamy对象,然后将数据传入AntiSamy对象进行过滤即可

// 需要过滤的数据String taintedHTML = "<script>alert(\"xss\");</script>HELLO WORD!";// 根据策略文件创建过滤策略Policy policy = Policy.getInstance( "antisamy-ebay.xml");// 根据策略对数据进行过滤AntiSamy antiSamy = new AntiSamy();CleanResults cr = antiSamy.scan( taintedHTML, policy);  taintedHTML = cr.getCleanHTML();

对于一个项目来说,基本每个输入都需要进行检查,所以一般我们会结合Filter进行使用。

Filter是一个典型的过滤链,可以用来对 HttpServletRequest 进行预处理,或者是对 HttpServlerResponse 进行后处理。

定义自定义过滤器 XssFilter 类,实现 Filter 接口,并对 doFilter( ServletRequest request, ServletResponse response, FilterChain chain) 方法进行重写。为了对用户请求进行处理,需要重写 ServletRequest ,并交由 FilterChain 执行

/** * XSS (Cross Site Scripting) 过滤器 * @author zhangcs */public class XssFilter implements Filter{    @SuppressWarnings("unused")    private FilterConfig filterConfig;    @Override    public void init(FilterConfig filterConfig) throws ServletException {        this.filterConfig = filterConfig;    }    @Override    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)            throws IOException, ServletException {        // 传入重写后的Request        chain.doFilter( new XssRequestWrapper( ( HttpServletRequest)request), response);    }    @Override    public void destroy() {        this.filterConfig = null;    }}

新建一个自定义 HttpServletRequest 包装类 XssRequestWrapper ,继承 HttpServletRequestWrapper 类,并对getParameter( String param)getParameterValues( String param)以及 getHeader( String param) 等方法进行重写。

例如我们使用的MVC框架为SpringMVC,需要对用户输入的参数值进行过滤,则重写 getParameterValues( String name) 方法

/** * 自定义的XSS请求包装器 * @author zhangcs */public class XssRequestWrapper extends HttpServletRequestWrapper {    public XssRequestWrapper( HttpServletRequest request) {        super(request);    }    @Override    public String[] getParameterValues( String name){          String[] values = super.getParameterValues( name);          if ( values == null){            return null;          }        int len = values.length;        String[] newArray = new String[len];        for (int j = 0; j < len; j++){            // 过滤            newArray[j] = xssClean( values[j]);        }        return newArray;    }    /**      * 策略文件     * 注意,需要将要使用的策略文件放到项目资源文件路径下      * */    private static String antiSamyPath = XssRequestWrapper.class.getClassLoader()            .getResource( "antisamy-ebay.xml").getFile();    /**     * AntiSamy过滤数据     * @param taintedHTML 需要进行过滤的数据     * @return 返回过滤后的数据     * */    private String xssClean( String taintedHTML){          try{            // 指定策略文件            Policy policy = Policy.getInstance( antiSamyPath);            // 使用AntiSamy进行过滤            AntiSamy antiSamy = new AntiSamy();             CleanResults cr = antiSamy.scan( taintedHTML, policy);              taintedHTML = cr.getCleanHTML();        }catch( ScanException e) {              e.printStackTrace();        }catch( PolicyException e) {              e.printStackTrace();        }        return taintedHTML;    }}

Filter对象将会在web应用启动时由服务器根据 web.xml 文件中的配置信息来创建,所以还需要在 web.xml 文件中配置注册自定义的 XssFilter

<!-- 注册XssFilter --><filter>  <filter-name>XSSFilter</filter-name >  <filter-class>cn.ghr.ehr.filter.XssFilter</filter-class >  <init-param>    <param-name>encoding</param-name>    <param-value>UTF-8</param-value>  </init-param></filter><!-- 配置需要过滤的请求 --><filter-mapping>  <filter-name>XSSFilter</filter-name >  <url-pattern>/</url-pattern></filter-mapping>
原创粉丝点击