SpringBoot过滤XSS脚本攻击

置顶 精帖
1 29
大海无量
大海无量 博主 2019-08-18 17:56

xss攻击是网站避免不了的问题,在过滤器中替换alert等关键词也可以做到,但是可能考虑没有那么完备,那么就用现成的一些方案吧,我选择antisamy,引入maven,然后新建一个过滤器,按照下面的教程建好类就可以了,另外还要 antisamy的配置文件放在resource下面,xss就解决了。

1.前言

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

Antisamy的对包含非法字符的过滤依赖于策略文件,策略文件规定了 AntiSamy 对各个标签、属性的处理方法。策略文件定义的严格与否,决定了AntiSamy 对 xss 漏洞的防御效果。

2.使用方法

2.1 到 AntiSamy 官网下载策略文件,添加到项目中。

2.2 maven 导入 jar 包。

<dependency>
    <groupId>org.owasp.antisamy</groupId>
    <artifactId>antisamy</artifactId>
    <version>1.5.8</version>
</dependency>

2.3 新建过滤器。 

public class XssFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
                         FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;
        filterChain.doFilter(new XssRequestWrapper(req), resp);
    }

    @Override
    public void destroy() {
    }
}

 

2.4 重写 request,新建一个类继承 HttpServletRequestWrapper,重写 getParameterMap() 方法,以及过滤非法字符的方法xssClean()。

public class XssRequestWrapper extends HttpServletRequestWrapper {
    private static final Logger logger = LoggerFactory.getLogger(XssRequestWrapper.class);
    private static Policy policy = null;

    static {
        //初始化策略
        /**
         * antisamy-anythinggoes.xml    非常危险,允许HTML、CSS、Javascript通过
         * antisamy-ebay.xml    相对安全,对内容进行过滤。适用于电子商务网站,允许用户输入HTML脚本作为页面的一部分
         * antisamy-myspace.xml 相对危险,适用于社交网站,允许用户输入作为整个页面
         * antisamy-slashdot.xml    适用于新闻网站的评论过滤
         * antisamy-tinymce.xml 相对安全,只允许文本格式通过
         */
        String path = XssRequestWrapper.class.getClassLoader().getResource("antisamy-tinymce-1.4.4.xml").getFile();
        try {
            policy = Policy.getInstance(path);
        } catch (PolicyException e) {
            logger.error("加载Antisamy策略文件时异常");
        }
    }

    public XssRequestWrapper(HttpServletRequest request) {
        super(request);
    }

    @Override
    public String getParameter(String paramString) {
        String str = super.getParameter(paramString);
        return StringUtils.isBlank(str) ? null : xssClean(str);
    }

    @Override
    public String getHeader(String paramString) {
        String str = super.getHeader(paramString);
        return StringUtils.isBlank(str) ? null : xssClean(str);
    }

    @SuppressWarnings("rawtypes")
    public Map<String, String[]> getParameterMap() {
        Map<String, String[]> request_map = super.getParameterMap();
        Iterator iterator = request_map.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry me = (Map.Entry) iterator.next();
            String[] values = (String[]) me.getValue();
            for (int i = 0; i < values.length; i++) {
                values[i] = xssClean(values[i]);
            }
        }
        return request_map;
    }

    @Override
    public String[] getParameterValues(String paramString) {
        String[] arrayOfString1 = super.getParameterValues(paramString);
        if (arrayOfString1 == null)
            return null;
        int i = arrayOfString1.length;
        String[] arrayOfString2 = new String[i];
        for (int j = 0; j < i; j++)
            arrayOfString2[j] = xssClean(arrayOfString1[j]);
        return arrayOfString2;
    }

    private String xssClean(String value) {
        AntiSamy antiSamy = new AntiSamy();
        try {
            final CleanResults cr = antiSamy.scan(value, policy);
            // 安全的HTML输出
            String resultValue = cr.getCleanHTML();
            //对转义的html特殊字符进行反转义,如 <、>、" 等
            return StringEscapeUtils.unescapeHtml3(resultValue);
        } catch (Exception e) {
            logger.error("Antisamy过滤特殊字符时出错");
        }
        return value;
    }
}

2.5 测试。在接收参数的地方控制台输出参数,会发现,类似 “javascript、onclick、style” 等特殊字符均会被过滤。当然,字符是否被过滤,或者过滤的方式,可以在策略文件中设置。

3.策略文件

Antisamy有种策略文件模版,用户可以根据场景选择。

antisamy-anythinggoes.xml    非常危险,允许HTML、CSS、Javascript通过
antisamy-ebay.xml    相对安全,对内容进行过滤。适用于电子商务网站,允许用户输入HTML脚本作为页面的一部分
antisamy-myspace.xml 相对危险,适用于社交网站,允许用户输入作为整个页面
antisamy-slashdot.xml    适用于新闻网站的评论过滤
antisamy-tinymce.xml 相对安全,只允许文本格式通过

 

策略文件为xml格式,除去xml文件头外,可以为7个部分,各部分的详细描述请参见: AntiSamy 策略文件详解

其中,重点关注 <tag-rules> 部分,此部分负责标签的处理策略(remove、truncate、validate)。

4.注意事项

4.1 如果项目启动,报错:NoClassDefFoundError: org/w3c/dom/ElementTraversal。请在 maven 中引入以下 jar 包(注意版本)。这是由于在读取策略文件时,需要用到 ElementTraversal 类,引用的 xml-apis.jar 版本中需要包含 ElementTraversal 类才可以。

<dependency>
    <groupId>xml-apis</groupId>
    <artifactId>xml-apis</artifactId>
    <version>1.4.01</version>
</dependency>

4.2 字符转译问题

如下代码,在调用 antiSamy.scan(value, policy) 时,value 中的特殊字符(如:<、>、"等)会被转译。如果传递的是 json 格式的数据,需要将转义后的数据进行反转义。

private String xssClean(String value) {
    AntiSamy antiSamy = new AntiSamy();
    try {
        final CleanResults cr = antiSamy.scan(value, policy);
        // 安全的HTML输出
        String resultValue = cr.getCleanHTML();
        //对转义的html特殊字符进行反转义,如 <、>、" 等
        return StringEscapeUtils.unescapeHtml3(resultValue);
    } catch (Exception e) {
        logger.error("Antisamy过滤特殊字符时出错");
    }
    return value;
}
回帖