XSS跨站攻击解决办法--AntiSamy的配置及使用

7 篇文章 0 订阅

XSS跨站攻击

        跨站脚本攻击(Cross Site Scripting),为了不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS。恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。

XSS分为:存储型和反射型
存储型XSS:存储型XSS,持久化,代码是存储在服务器中的,如在个人信息或发表文章等地方,加入代码,如果没有过滤或过滤不严,那么这些代码将储存到服务器中,用户访问该页面的时候触发代码执行。这种XSS比较危险,容易造成蠕虫,盗窃cookie(虽然还有种DOM型XSS,但是也还是包括在存储型XSS内)。
反射型XSS:非持久化,需要欺骗用户自己去点击链接才能触发XSS代码(服务器中没有这样的页面和内容),一般容易出现在搜索页面。

AntiSamy介绍

   OWASP AntiSamy项目可以有好几种定义。从技术角度看,它是一个可确保用户输入的HTML/CSS符合应用规范的API。也可以这么说,它是个确保用户无法在HTML中提交恶意代码的API,而这些恶意代码通常被输入到个人资料、评论等会被服务端存储的数据中。在Web应用程序中,“恶意代码”通常是指 Javascript。同时层叠样式表(CSS)在调用Javascript引擎的时候也会被认为是恶意代码。当然在很多情况下,一些“正常”的HTML 和CSS也会被用于恶意的目的,所以我们也会对此予以处理。

使用AntiSamy防御XSS攻击

1. maven 工程引入AntiSamy

pom.xml中添加AntiSamy的依赖,直接导入到工程即可,其运行依赖的xercesImpl、batik、nekohtml默认会一起导入。
	 <dependency>  
            <groupId>org.owasp.antisamy</groupId>  
            <artifactId>antisamy</artifactId>  
            <version>1.5.3</version>  
        </dependency>

2. 策略文件

antisamy-slashdot.xml 

 Slashdot (http://www.slashdot.org/)是一个提供技术新闻的网站,它允许用户用有限的HTML格式的内容匿名回帖。
Slashdot不仅仅是目前同类中最酷的网站之一,而且同时也曾是最容易被成功攻击的网站之一。更不幸的是,导致大部分用户遭受攻击的原由是臭名昭着的goatse.cx 图片(请你不要刻意去看)。
Slashdot的安全策略非常严格:用户只能提交下列的html标签:<b>, <u>, <i>, <a>, <blockquote>,并且还不支持CSS.因此我们创建了这样的策略文件来实现类似的功能。它允许所有文本格式的标签来直接修饰字体、颜色或者强调作用。


antisamy-ebay.xml

 众所周知,eBay (http://www.ebay.com/)是当下最流行的在线拍卖网站之一。它是一个面向公众的站点,因此它允许任何人发布一系列富HTML的内容。我们对eBay成为一些复杂XSS攻击的目标,并对攻击者充满吸引力丝毫不感到奇怪。由于eBay允许输入的内容列表包含了比Slashdot更多的富文本内容,所以它的受攻击面也要大得多。


antisamy-myspace.xml

 MySpace (http://www.myspace.com/)是最流行的一个社交网站之一。用户允许提交几乎所有的他们想用的HTML和CSS,只要不包含JavaScript。MySpace现在用一个黑名单来验证用户输入的HTML,这就是为什么它曾受到Samy蠕虫攻击(http://namb.la/)的原因。Samy蠕虫攻击利用了一个本应该列入黑名单的单词(eval)来进行组合碎片攻击的,其实这也是AntiSamy立项的原因。


antisamy-anythinggoes.xml

 如果你想允许所有有效的HTML和CSS元素输入(但能拒绝JavaScript或跟CSS相关的网络钓鱼攻击),你可以使用这个策略文件。其实即使MySpace也没有这么疯狂。然而,它确实提供了一个很好的参考,因为它包含了对于每个元素的基本规则,所以你在裁剪其它策略文件的时候可以把它作为一个知识库。


antisamy-tinymce.xml

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


antisamy.xml

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

3. AntiSamy的使用

策略文件加载

策略文件只需要加载一次即可,避免每次使用时都加载一次,造成不必要的性能损失:

private static Policy policy = null;
    static{
        if (policy == null) {
            try {
                policy =  Policy.getInstance("/WEB-INF/classes/antisamy-slashdot.xml");
            } catch (PolicyException e) {
                log.warn("XssFilter - static policy instance error. PolicyException=" , e);
            }
        } 
    }

XSS过滤核心代码

/**
         * 过滤xss攻击违规输入, 2017, zhujq
         * @param value 待过滤字符串
         * @return
         */
        public String xssClean(String value){
            log.info("xssClean() - value=" + value + ", start. ");
            AntiSamy antiSamy = new AntiSamy();
            try {
                //Policy policy = Policy.getInstance(APIGlobal.XSS_ANTISAMY_FILE_PATH);
                final CleanResults cr = antiSamy.scan(value, policy);
                String cleanValue = cr.getCleanHTML();
                log.info("xssClean() - value=" + value + ", cleanValue=" + cleanValue);
                return cleanValue;
            } catch (PolicyException e) {
                log.warn("xssClean() - value=" + value + ", PolicyException=", e);
            } catch (ScanException e) {
                log.warn("xssClean() - value=" + value + ", ScanException=", e);
            } catch (Exception e) {
                log.warn("xssClean() - value=" + value + ", Exception=", e);
            } 
            return value;
        }
WEB过滤器
自定义过滤器XssFilter.java, 过滤接口请求参数, 代码r
   
/**
 * Copyright (c) 2017 21CN.COM . All rights reserved.
 *
 * Description: edrive-api-3.0
 * 
 * Modified log:
 * ------------------------------------------------------
 * Ver.		Date		Author			Description
 * ------------------------------------------------------
 * 1.0		2017-11-29	jinQiang.zhu	        created.
 */
package com.cn21.edrive.product.api.rest.test;

import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.owasp.validator.html.AntiSamy;
import org.owasp.validator.html.CleanResults;
import org.owasp.validator.html.Policy;
import org.owasp.validator.html.PolicyException;
import org.owasp.validator.html.ScanException;

import com.cn21.edrive.adaptor.weibo.util.ReadPropertiesFile;
import com.cn21.edrive.product.api.rest.APIGlobal;

/**
 * @author jinQiang.zhu
 *
 */
public class XssFilter implements Filter{


    
    private static final Logger log = Logger.getLogger(XssFilter.class);
    private FilterConfig filterConfig; 
    private static Policy policy = null;
   
    static{
        if (policy == null) {
            try {
                policy =  Policy.getInstance("/WEB-INF/classes/antisamy-slashdot.xml");
            } catch (PolicyException e) {
                log.warn("XssFilter - static policy instance error. PolicyException=" , e);
            }
        } 
       
    }

    /* (non-Javadoc)
     * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }

    /* (non-Javadoc)
     * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
                                                                                             ServletException {
        log.debug("doFilter() - start. ");
        chain.doFilter(new XssRequestWapper((HttpServletRequest) request), response);    
        
        
    }

    /* (non-Javadoc)
     * @see javax.servlet.Filter#destroy()
     */
    @Override
    public void destroy() {
        this.filterConfig = null;
        
    }
    
    
    class XssRequestWapper extends HttpServletRequestWrapper{
        /**
         * @param request
         */
        public XssRequestWapper(HttpServletRequest request){
            super(request);
        }
        
        
        /* (non-Javadoc)
         * @see javax.servlet.ServletRequestWrapper#getParameterMap()
         * 覆盖父类方法
         */
        @SuppressWarnings({ "rawtypes", "unchecked" })  
        public Map<String,String[]> getParameterMap(){  
            log.debug("getParameterMap() - start. ");
            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++){  
                     //System.out.println(values[i]);  
                      values[i] = xssClean(values[i]);  
                 }  
            }  
            return request_map;  
        }
        
        /* (non-Javadoc)
         * @see javax.servlet.ServletRequestWrapper#getParameter(java.lang.String)
         * 覆盖父类方法
         */
        @SuppressWarnings({ "rawtypes", "unchecked" })  
        public String getParameter(String name) { 
            log.debug("getParameter() - start. ");
            String v=super.getParameter(name);  
            if(v==null)  
                return null; 
            if (needXssFilter) {
               v = xssClean(v);
            }
            return v;  
        }  
          
        /* (non-Javadoc)
         * @see javax.servlet.ServletRequestWrapper#getParameterValues(java.lang.String)
         * 覆盖父类方法
         */
        @SuppressWarnings({ "rawtypes", "unchecked" })  
        public String[] getParameterValues(String name) {  
            log.debug("getParameterValues() - start. ");
            String[] v=super.getParameterValues(name);  
            if(v==null || v.length==0)  
                return v; 
            if (needXssFilter) {
                for(int i=0;i<v.length;i++){  
                    v[i]=xssClean(v[i]);  
                }  
            }
            return v;  
        }     
        
        /**
         * 过滤xss攻击违规输入, 2017, zhujq
         * @param value
         * @return
         */
        private String xssClean(String value){
            log.info("xssClean() - value=" + value + ", start. ");
            AntiSamy antiSamy = new AntiSamy();
            try {
                //antiSamy无法将编码后的字符进行过滤,所以统一进行decode
                value = URLDecoder.decode(value, "utf-8");
                final CleanResults cr = antiSamy.scan(value, policy);
                String cleanValue = cr.getCleanHTML();
                //antiSamy会将双引号转换成""所以对过滤后的字符进行处理
                cleanValue = StringEscapeUtils.unescapeHtml(cleanValue);
                log.info("xssClean() - value=" + value + ", cleanValue=" + cleanValue);
                return cleanValue;
            } catch (PolicyException e) {
                log.warn("xssClean() - value=" + value + ", PolicyException=", e);
            } catch (ScanException e) {
                log.warn("xssClean() - value=" + value + ", ScanException=", e);
            } catch (Exception e) {
                log.warn("xssClean() - value=" + value + ", Exception=", e);
            } 
            return value;
        }
        
    }

}

过滤器web.xml配置

 Filter对象将会在web应用启动时由服务器根据  web.xml  文件中的配置信息来创建,所以还需要在  web.xml  文件中配置注册自定义的  XssFilter,自定义filter必须放在默认过滤器之前。
<!-- xss 过滤 -->
	<filter>
		<filter-name>XssFilter</filter-name>
		<filter-class>com.cn21.edrive.product.api.rest.test.XssFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>XssFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<filter>
		<filter-name>struts2</filter-name>
		<filter-class>
			org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
		</filter-class>
	</filter>

	<filter-mapping>
		<filter-name>struts2</filter-name>
		<url-pattern>/*</url-pattern>   	<!-- 把*.action 改为 /* -->
		<dispatcher>REQUEST</dispatcher>    <!-- 别忘了添加这两个参数 -->
		<dispatcher>FORWARD</dispatcher>
	</filter-mapping>




        
 
         


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值