Java中使用AntiSamy开源项目防御XSS攻击

背景:

不久前公司有接了一个国土的项目,虽然是内部小项目,但可能因为是zhengfu项目,竟然找软件测试公司去大概测了一下。。。然后出现了以下三种问题:sql注入,XSS攻击,接口访问频率。下面是解决XSS攻击。

研究:

一开始的想法是,弄个过滤器把那些关键字过滤掉不就好了,例如script、eval、document等等,确实网上也有这些例子。可参考此博客https://www.cnblogs.com/myyBlog/p/8890365.html

但是人家可是请专业的软件测试工程师测试的,我这么混过去肯定是不行滴,上面的主要只是简单地过滤掉用户的输入参数,而且过滤得非常的不全面,可能还有多方面的跨站脚本攻击呢?然后继续的百度找找有没有此方面的开源项目。结果真的找到了一个,就是AntiSamy,OWASP的一个开源项目,通过对用户输入的 HTML / CSS / JavaScript 等内容进行检验和清理,确保输入符合应用规范。AntiSamy被广泛应用于Web服务对存储型和反射型XSS的防御中。这个就相当的强大了啊。

方案:

参考上面的博客的做法:自定义一个过滤器XssFilter,拦截所有路径。在doFilter中使用HttpServletRequestWrapper来包装一下HttpServletRequest(进行XSS清洗达到防御XSS攻击),最后交给filterChain往下执行。嗯,就这么大概了,网友真强大~

开工:

1、引入Maven依赖:

<!-- OWASP AntiSamy 防止XSS攻击-->
<dependency>
    <groupId>org.owasp.antisamy</groupId>
    <artifactId>antisamy</artifactId>
    <version>1.5.5</version>
</dependency>

2、策略文件:

Maven下载下来的依赖里面是带有策略文件,之前试过前一点的版本例如1.5.3好像是没有的。下面我使用的策略文件将是antisamy-ebay.xml,毕竟eBay是当下最流行的在线拍卖网站之一,防御策略肯定是非常好的。关于AntiSamy的策略文件的详解大家可以去搜一下,毕竟可能以后要改里面的处理规则呢。

各种策略文件


3、怎么使用AntiSamy:

想当的简单,首先要指定策略文件生成Policy,然后新建AntiSamy,再对需要进行XSS清洗的内容进行扫面即可。

String xsshtml = "hyf<script>alert(1)</script>";
Policy policy = Policy.getInstance("antiSamyPath");
AntiSamy antiSamy = new AntiSamy();
CleanRequests cr = antiSamy.scan(xsshtml,policy);
xsshtml = cr.getCleanHTML(); //清洗完的

4、创建XssFilter实现Filter接口然后重写doFilter方法:

因为我们对用户的每次请求都进行拦截清洗,清洗完才能真正地调用Controller的方法,所以我们用到的是过滤器而不是拦截器。因为Filter是一个典型的过滤链,可以用来对 HttpServletRequest 进行预处理,或者是对 HttpServlerResponse 进行后处理。

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
 *
 *@author howinfun
 *@date 2018/10/23
 *@company DM
 *@version 1.0
 */
public class XssFilter implements Filter {

    private FilterConfig filterConfig;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)servletRequest;
       /* filterChain.doFilter(new XssHttpServletRequestWrapper2(request),servletResponse);*/
        filterChain.doFilter(new XssHttpServletRequestWrapper(request),servletResponse);
    }

    @Override
    public void destroy() {
        this.filterConfig = null;
    }
}

5、新建一个自定义 HttpServletRequest 包装类 XssHttpServletRequestWrapper :

继承 HttpServletRequestWrapper 类,对getParameter( String param)、getParameterValues( String param)以及 getHeader( String param) 等方法进行重写,都将进行一遍全方位清洗。

import org.apache.commons.lang.StringEscapeUtils;
import org.jeecgframework.web.appconfig.util.StringUtils;
import org.owasp.validator.html.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.Iterator;
import java.util.Map;

/**
 * @desc 基于AntiSamy的XSS防御
 * @author howinfun
 * @date 2018/10/23
 * @company DM
 * @version 1.0
 */
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {

    //AntiSamy使用的策略文件
    private static Policy policy = null;
    static {
        String antiSamyPath = XssHttpServletRequestWrapper.class.getClassLoader().getResource("antisamy-ebay.xml").getFile();
        System.out.println("policy_filepath:"+antiSamyPath);
        if(antiSamyPath.startsWith("file")){
            antiSamyPath = antiSamyPath.substring(6);
        }
        try {
            policy = Policy.getInstance(antiSamyPath);
        } catch (PolicyException e) {
            e.printStackTrace();
        }
    }


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

    /**
     * @desc Header为空直接返回,不然进行XSS清洗
     * @author howinfun
     * @date 2018/10/24
     *
     */
    @Override
    public String getHeader(String name) {
        String value = super.getHeader(name);
        if(StringUtils.isEmpty(value)){
            return value;
        }
        else{
            String newValue = cleanXSS(value);
            return newValue;
        }

    }

    /**
     * @desc Parameter为空直接返回,不然进行XSS清洗
     * @author howinfun
     * @date 2018/10/24
     *
     */
    @Override
    public String getParameter(String name) {
        String value = super.getParameter(name);
        if(StringUtils.isEmpty(value)){
            return value;
        }
        else{
            value = cleanXSS(value);
            return value;
        }
    }

    /**
     * @desc 对用户输入的参数值进行XSS清洗
     * @author howinfun
     * @date 2018/10/24
     *
     */
    @Override
    public String[] getParameterValues(String name) {
        String[] values = super.getParameterValues(name);
        if (values != null) {
            int length = values.length;
            String[] escapseValues = new String[length];
            for (int i = 0; i < length; i++) {
                escapseValues[i] = cleanXSS(values[i]);
            }
            return escapseValues;
        }
        return super.getParameterValues(name);
    }


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


    /**
     * @desc AntiSamy清洗数据
     * @author howinfun
     * @date 2018/10/24
     *
     */
    private String cleanXSS(String taintedHTML) {
        try{
            AntiSamy antiSamy = new AntiSamy();
            CleanResults cr = antiSamy.scan(taintedHTML, policy);//扫描
            taintedHTML = cr.getCleanHTML();//获取清洗后的结果
            return taintedHTML;
        }catch( ScanException e) {
            e.printStackTrace();
        }catch( PolicyException e) {
            e.printStackTrace();
        }
        return taintedHTML;
    }
}

6、在web.xml对新建的Filter进行注册。

<!-- 防止XSS攻击 -->
<filter>
  <filter-name>XSSFilter</filter-name>
  <filter-class>org.jeecgframework.core.filter.XssFilter</filter-class>
</filter>

<filter-mapping>
  <filter-name>XSSFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

7、接下来进行测试:

简单的测试是否能过滤掉script标签及里面的内容。


GIF.gif

8、继续测试:

我继续测试其他接口,测试了一个之前自己做的通用API,发现传回来的JSON数据出现了问题,原来的双引号被转换为&quot;。还有网友发现&nbsp;也会被转成乱码了。所以我们必须在清洗完后进行进一步处理,将这两个问题给自己解决掉。

/**
     * @desc AntiSamy清洗数据
     * @author howinfun
     * @date 2018/10/24
     *
     */
    private String cleanXSS(String taintedHTML) {
        try{
            AntiSamy antiSamy = new AntiSamy();
            final CleanResults cr = antiSamy.scan(taintedHTML,policy);
            //AntiSamy会把“&nbsp;”转换成乱码,把双引号转换成"&quot;" 先将&nbsp;的乱码替换为空,双引号的乱码替换为双引号
            String str = StringEscapeUtils.unescapeHtml(cr.getCleanHTML());
            str = str.replaceAll(antiSamy.scan("&nbsp;",policy).getCleanHTML(),"");
            str = str.replaceAll(antiSamy.scan("\"",policy).getCleanHTML(),"\"");
            return str;

        }catch( ScanException | PolicyException e) {
            e.printStackTrace();
        }
        return taintedHTML;
    }

到此,全部结束~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容

  • 本文包括:1、Filter简介2、Filter是如何实现拦截的?3、Filter开发入门4、Filter的生命周期...
    廖少少阅读 7,144评论 3 56
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,087评论 18 139
  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架,建立于...
    Hsinwong阅读 21,744评论 1 92
  • 即使,所有的努力都是无济于事,即使,所有的命运都早已注定,我大概还是要挣扎下去,不管以多难看的姿势。
    何事闭门剪西窗阅读 125评论 0 0
  • 文|青三盗 “叮铃铃,叮铃铃” 上课铃声响起,喧闹的校园顿时安静了下来,不是因为红土地操场飘扬的飞尘,看不出刚才还...
    青三盗阅读 301评论 0 0