防止XSS跨站脚本攻击:Java过滤器

Spring 同时被 2 个专栏收录
34 篇文章 0 订阅
139 篇文章 2 订阅

XSS问题描述

跨站脚本(Cross site script,简称xss)是一种“HTML注入”,由于攻击的脚本多数时候是跨域的,所以称之为“跨域脚本”。

我们常常听到“注入”(Injection),如SQL注入,那么到底“注入”是什么?注入本质上就是把输入的数据变成可执行的程序语句。SQL注入是如此,XSS也如此,只不过XSS一般注入的是恶意的脚本代码,这些脚本代码可以用来获取合法用户的数据,如Cookie信息。

或者当访问者浏览网页时恶意代码会被执行或者通过给管理员发信息的方式诱使管理员浏览,从而获得管理员权限,控制整个网站

攻击者利用跨站请求伪造能够轻松地强迫用户的浏览器发出非故意的HTTP请求,如诈骗性的电汇请求、修改口令和下载非法的内容等请求。

 

风险等级:

XSS风险分析

该漏洞可能被攻击者利用窃取或操纵客户会话和Cookie,它们可能用于模仿合法用户,从而使黑客能够以合法用户身份登录系统进行渗透。可执行攻击者恶意脚本。

XSS 注入方法

在 HTML 中内嵌的文本中,恶意内容以 script 标签形成注入。

在内联的 JavaScript 中,拼接的数据突破了原本的限制(字符串,变量,方法名等)。

在标签属性中,恶意内容包含引号,从而突破属性值的限制,注入其他属性或者标签。

在标签的 href、src 等属性中,包含 javascript: 等可执行代码。

在 onload、onerror、onclick 等事件中,注入不受控制代码。

在 style 属性和标签中,包含类似 background-image:url("javascript:…"); 的代码(新版本浏览器已经可以防范)。

在 style 属性和标签中,包含类似 expression(…) 的 CSS 表达式代码(新版本浏览器已经可以防范)。

XSS 防御

本文基于JavaWeb后端考虑,前端可参考: 前端安全系列:如何防止XSS攻击?

依赖jar

<dependency>
	<groupId>javax.servlet</groupId>
	<artifactId>servlet-api</artifactId>
	<version>3.0-alpha-1</version>
	<scope>provided</scope>
</dependency>

web.xml添加过滤器

<!-- 解决xss漏洞 -->
<filter>
	<filter-name>xssFilter</filter-name>
	<filter-class>com.newcapec.cloudpay.filter.XssFilter</filter-class>
</filter>
<!-- 解决xss漏洞 -->
<filter-mapping>
	<filter-name>xssFilter</filter-name>
	<!--过滤路径-->
	<url-pattern>*</url-pattern>
</filter-mapping>

过滤器

自定义过滤器Filter拦截请求,并对请求参数进行xss过滤处理

package com.newcapec.cloudpay.filter;


import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;


/**
 * @Title: XSS过滤器
 * @ClassName: com.newcapec.cloudpay.filter.XssFilter.java
 * @Description:
 *
 * @Copyright 2016-2018  Powered By 研发中心
 * @author: 王延飞
 * @date:  2019-01-24 16:22
 * @version V1.0
 */
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 {
        //使用包装器
        XSSRequestWrapper XSSRequestWrapper=new XSSRequestWrapper((HttpServletRequest) servletRequest);
        filterChain.doFilter(XSSRequestWrapper,servletResponse);
    }

    @Override
    public void destroy() {

    }
}

过滤器包装器

package com.newcapec.cloudpay.filter;

import org.apache.commons.lang.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;


/**
 * @version V1.0
 * @Title: Request的包装类
 * @ClassName: com.newcapec.cloudpay.filter.XSSRequestWrapper.java
 * @Description: XSSRequestWrapper是Request的包装类, 用于修改Request请求,这是拦截器Interceptor所不能做到的
 * @Copyright 2016-2018  Powered By 研发中心
 * @author: 王延飞
 * @date: 2019-01-25 9:15
 */
public class XSSRequestWrapper extends HttpServletRequestWrapper {


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


    /**
     * @param name
     * @return java.lang.String[]
     * @Title: 对数组参数进行特殊字符过滤
     * @methodName: getParameterValues
     * @Description:
     * @author: 王延飞
     * @date: 2019-01-25 10:23
     */
    @Override
    public String[] getParameterValues(String name) {

        String[] values = super.getParameterValues(name);
        if (values == null) {
            return null;
        }
        int count = values.length;
        String[] encodedValues = new String[count];
        for (int i = 0; i < count; i++) {
            encodedValues[i] = clearXss(values[i]);
        }
        return encodedValues;
    }

    /**
     * @param name
     * @return java.lang.String
     * @Title: 对参数中特殊字符进行过滤
     * @methodName: getParameter
     * @Description:
     * @author: 王延飞
     * @date: 2019-01-25 10:23
     */
    @Override
    public String getParameter(String name) {
        String value = super.getParameter(name);
        if (value == null) {
            return null;
        }
        return clearXss(value);
    }

    /**
     * @Title: 覆盖getParameterMap方法,将参数名和参数值都做xss & sql过滤
     * @methodName:  getParameterMap
     * @param
     * @return java.util.Map
     * @Description: 覆盖getParameterMap方法,将参数名和参数值都做xss & sql过滤
     * 【一般post表单请求,或者前台接收为实体需要这样处理】
     *
     * @author: 王延飞
     * @date:  2019-02-20 11:12
     */
    @Override
    public Map getParameterMap() {

        Map<String, Object> paramMap = new HashMap<String, Object>();
        Map<String, String[]> requestMap = super.getParameterMap();
        Iterator<Entry<String, String[]>> it = requestMap.entrySet().iterator();
        while (it.hasNext()) {
            Entry<String, String[]> entry = it.next();
            if(entry.getValue().length==1){
                paramMap.put(xssEncode(entry.getKey()), xssEncode(entry.getValue()[0]));
            } else {
                String[] values = entry.getValue();
                String value = "";
                for(int i=0; i<values.length; i++){
                    value = values[i] + ",";
                }
                value = value.substring(0, value.length()-1);
                paramMap.put(xssEncode(entry.getKey()), xssEncode(entry.getValue()[0]));
            }
        }
        return paramMap;
    }


    /**
     * @param name
     * @return java.lang.Object
     * @Title: 获取attribute, 特殊字符过滤
     * @methodName: getAttribute
     * @Description:
     * @author: 王延飞
     * @date: 2019-01-25 10:24
     */
    @Override
    public Object getAttribute(String name) {
        Object value = super.getAttribute(name);
        if (value != null && value instanceof String) {
            clearXss((String) value);
        }
        return value;
    }

    /**
     * @Title: 对请求头部进行特殊字符过滤
     * @methodName: getHeader
     * @param name
     * @return java.lang.String
     * @Description:
     *
     * @author: 王延飞
     * @date: 2019-01-25 10:34
     */
    /*@Override
    public String getHeader(String name) {

        String value = super.getHeader(name);
        if (value == null) {
            return null;
        }
        return clearXss(value);
    }*/

    /**
     * @param value
     * @return java.lang.String
     * @Title: 特殊字符处理(转义或删除)
     * @methodName: clearXss
     * @Description:
     * @author: 王延飞
     * @date: 2019-01-25 9:16
     */
    private String clearXss(String value) {

        if (StringUtils.isEmpty(value)) {
            return value;
        }

        // 字符编码不一致,需要转换。我们系统是UTF-8编码,这里不需要
        /*try {
            value = new String(value.getBytes("ISO8859-1"), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }*/

        return XssFilterUtil.stripXss(value);
    }

   
   /**
     * 将容易引起xss漏洞的半角字符直接替换成全角字符 在保证不删除数据的情况下保存
     *
     * @param s
     * @return 过滤后的值
     */
    private static String xssEncode(String value) {
        if (value == null || value.isEmpty()) {
            return value;
        }
        value = value.replaceAll("eval\\((.*)\\)", "");
        value = value.replaceAll("<","&lt;");
        value = value.replaceAll(">","&gt;");
        value = value.replaceAll("'","&apos;");
        value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
        value = value.replaceAll("(?i)<script.*?>.*?<script.*?>", "");
        value = value.replaceAll("(?i)<script.*?>.*?</script.*?>", "");
        value = value.replaceAll("(?i)<.*?javascript:.*?>.*?</.*?>", "");
        value = value.replaceAll("(?i)<.*?\\s+on.*?>.*?</.*?>", "");
//        value = value.replaceAll("[<>{}\\[\\];\\&]","");
        return value;
    }
}

 

过滤器工具类

package com.newcapec.cloudpay.filter;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @version V1.0
 * @Title:
 * @ClassName: com.newcapec.cloudpay.filter.XssFilterUtil.java
 * @Description:
 * @Copyright 2016-2018  Powered By 研发中心
 * @author: 王延飞
 * @date: 2019-01-25 9:11
 */
public class XssFilterUtil {

    private static final Logger log = LoggerFactory.getLogger(XssFilterUtil.class);

    private static List<Pattern> patterns = null;

    /**
     * @param
     * @return java.util.List<java.lang.Object                               [                               ]>
     * @Title: XSS常见攻击
     * @methodName: getXssPatternList
     * @Description: Pattern.MULTILINE(? m):在这种模式下,'^'和'$'分别匹配一行的开始和结束。此外,'^'仍然匹配字符串的开始,'$'也匹配字符串的结束。
     * 默认情况下,这两个表达式仅仅匹配字符串的开始和结束。
     * <p>
     * Pattern.DOTALL(?s) :在这种模式下,表达式'.'可以匹配任意字符,包括表示一行的结束符。
     * 默认情况下,表达式'.'不匹配行的结束符。
     * @author: 王延飞
     * @date: 2019-01-25 9:11
     */
    private static List<Object[]> getXssPatternList() {

        List<Object[]> ret = new ArrayList<Object[]>();

        ret.add(new Object[]{"<(no)?script[^>]*>.*?</(no)?script>", Pattern.CASE_INSENSITIVE});
        ret.add(new Object[]{"</script>", Pattern.CASE_INSENSITIVE});
        ret.add(new Object[]{"<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL});
        ret.add(new Object[]{"eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL});
        ret.add(new Object[]{"expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL});
        ret.add(new Object[]{"(javascript:|vbscript:|view-source:)*", Pattern.CASE_INSENSITIVE});
        ret.add(new Object[]{"<(\"[^\"]*\"|\'[^\']*\'|[^\'\">])*>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL});
        ret.add(new Object[]{"(window\\.location|window\\.|\\.location|document\\.cookie|document\\.|alert\\(.*?\\)|window\\.open\\()*", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL});
        ret.add(new Object[]{"<+\\s*\\w*\\s*(oncontrolselect|oncopy|oncut|ondataavailable|ondatasetchanged|ondatasetcomplete|ondblclick|ondeactivate|ondrag|ondragend|ondragenter|ondragleave|ondragover|ondragstart|ondrop|onerror=|onerroupdate|onfilterchange|onfinish|onfocus|onfocusin|onfocusout|onhelp|onkeydown|onkeypress|onkeyup|onlayoutcomplete|onload|onlosecapture|onmousedown|onmouseenter|onmouseleave|onmousemove|onmousout|onmouseover|onmouseup|onmousewheel|onmove|onmoveend|onmovestart|onabort|onactivate|onafterprint|onafterupdate|onbefore|onbeforeactivate|onbeforecopy|onbeforecut|onbeforedeactivate|onbeforeeditocus|onbeforepaste|onbeforeprint|onbeforeunload|onbeforeupdate|onblur|onbounce|oncellchange|onchange|onclick|oncontextmenu|onpaste|onpropertychange|onreadystatechange|onreset|onresize|onresizend|onresizestart|onrowenter|onrowexit|onrowsdelete|onrowsinserted|onscroll|onselect|onselectionchange|onselectstart|onstart|onstop|onsubmit|onunload)+\\s*=+", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL});
        return ret;
    }

    /**
     * @param
     * @return java.util.List<java.util.regex.Pattern>
     * @Title: XSS常见攻击-正则表达式
     * @methodName: getPatterns
     * @Description:
     * @author: 王延飞
     * @date: 2019-01-25 9:11
     */
    private static List<Pattern> getPatterns() {


        if (patterns == null) {

            List<Pattern> list = new ArrayList<Pattern>();

            String regex = null;
            Integer flag = null;
            int arrLength = 0;

            for (Object[] arr : getXssPatternList()) {
                arrLength = arr.length;
                for (int i = 0; i < arrLength; i++) {
                    regex = (String) arr[0];
                    flag = (Integer) arr[1];
                    list.add(Pattern.compile(regex, flag));
                }
            }

            patterns = list;
        }

        return patterns;
    }

    /**
     * @param value
     * @return java.lang.String
     * @Title: 处理特殊字符
     * @methodName: stripXss
     * @Description: 如果是特殊字符,策略有两种:转义或删除
     * @author: 王延飞
     * @date: 2019-01-25 9:12
     */
    public static String stripXss(String value) {

        if (StringUtils.isNotBlank(value)) {

            log.info("【XSS攻击防御】,接收字符是:{}", value);

            //
            Matcher matcher = null;

            for (Pattern pattern : getPatterns()) {
                matcher = pattern.matcher(value);
                // 匹配
                if (matcher.find()) {
                    // 删除相关字符串
                    value = matcher.replaceAll("");
                }
            }

            log.info("【XSS攻击防御】,匹配正则是:{},处理后是:{}", matcher, value);

            /**
             * 替换为转移字符,类似HtmlUtils.htmlEscape
             */
            //value = value.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
            //删除特殊符号
            //String specialStr = "%20|=|!=|-|--|;|'|\"|%|#|+|//|/| |\\|<|>|(|)|{|}";

            if (StringUtils.isNotBlank(value)) {
                String specialStr = "%20|=|!=|-|--|;|'|\"|%|#|[+]|//|/| |\\|<|>|(|)|{|}";
                for (String str : specialStr.split("\\|")) {
                    if (value.indexOf(str) > -1) {
                        value = value.replaceAll(str, "");

                    }
                }
                log.info("【XSS攻击防御】,特殊符号处理后是:{}", value);
            }


        }


        return value;
    }

   
}

测试类

package com.newcapec.cloudpay.controller.test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;

/**
 * @Title: Controller--测试
 * @ClassName:RsaControllerTest.java
 * @Description:
 *
 * @Copyright 2016-2017  Powered By 研发中心
 * @author: 王延飞
 * @version V1.0
 */
@Controller
@RequestMapping("/test")
public class RsaControllerTest {

    private static final Logger log = LoggerFactory.getLogger(RsaControllerTest.class);


    @RequestMapping("/testXSS")
    @ResponseBody
    public String testXSS(HttpServletRequest request){

		/*String queryString = request.getQueryString();
		log.info("【防御XSS】,客户端端请求参数是:{}", queryString);*/

        String name = request.getParameter("name");
        log.info("【防御XSS】,客户端端name是:{}", name);

        return "【防御XSS】,客户端端请求参数:" +name;
    }
}

测试结果

访问:http://localhost:8080/CloudPayment/test/testXSS.do?name=<script>alert('你被攻击了!')</script>

  • 控制台输出信息: 

2019-01-25 11:50:37:512 com.newcapec.cloudpay.filter.XssFilterUtil.stripXss(XssFilterUtil.java:104) 【XSS攻击防御】,接收字符是:<script>alert('你被攻击了!')</script>
2019-01-25 11:50:37:513 com.newcapec.cloudpay.filter.XssFilterUtil.stripXss(XssFilterUtil.java:118) 【XSS攻击防御】,匹配正则是:java.util.regex.Matcher[pattern=<+\s*\w*\s*(oncontrolselect|oncopy|oncut|ondataavailable|ondatasetchanged|ondatasetcomplete|ondblclick|ondeactivate|ondrag|ondragend|ondragenter|ondragleave|ondragover|ondragstart|ondrop|οnerrοr=|onerroupdate|onfilterchange|onfinish|onfocus|onfocusin|onfocusout|onhelp|onkeydown|onkeypress|onkeyup|onlayoutcomplete|onload|onlosecapture|onmousedown|onmouseenter|onmouseleave|onmousemove|onmousout|onmouseover|onmouseup|onmousewheel|onmove|onmoveend|onmovestart|onabort|onactivate|onafterprint|onafterupdate|onbefore|onbeforeactivate|onbeforecopy|onbeforecut|onbeforedeactivate|onbeforeeditocus|onbeforepaste|onbeforeprint|onbeforeunload|onbeforeupdate|onblur|onbounce|oncellchange|onchange|onclick|oncontextmenu|onpaste|onpropertychange|onreadystatechange|onreset|onresize|onresizend|onresizestart|onrowenter|onrowexit|onrowsdelete|onrowsinserted|onscroll|onselect|onselectionchange|onselectstart|onstart|onstop|onsubmit|onunload)+\s*=+ region=0,0 lastmatch=],处理后是:
2019-01-25 11:50:37:513 com.newcapec.cloudpay.controller.test.RsaControllerTest.testXSS(RsaControllerTest.java:64) 【防御XSS】,客户端端name是:

  • 4
    点赞
  • 8
    评论
  • 14
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

打赏
文章很值,打赏犒劳作者一下
相关推荐
一、什么是XSS攻击 XSS是一种经常出现在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。比如这些代码包括HTML代码和客户端脚本攻击者利用XSS漏洞旁路掉访问控制——例如同源策略(same origin policy)。这种类型的漏洞由于被黑客用来编写危害性更大的网络钓鱼(Phishing)攻击而变得广为人知。对于跨站脚本攻击,黑客界共识是:跨站脚本攻击是新型的“缓冲区溢出攻击“,而JavaScript是新型的“ShellCode”。 二、XSS漏洞的危害 (1)网络钓鱼,包括盗取各类用户账号; (2)窃取用户cookies资料,从而获取用户隐私信息,或利用用户身份进一步对网站执行操作; (3)劫持用户(浏览器)会话,从而执行任意操作,例如进行非法转账、强制发表日志、发送电子邮件等; (4)强制弹出广告页面、刷流量等; (5)网页挂马; (6)进行恶意操作,例如任意篡改页面信息、删除文章等; (7)进行大量的客户端攻击,如DDoS攻击; (8)获取客户端信息,例如用户的浏览历史、真实IP、开放端口等; (9)控制受害者机器向其他网站发起攻击; (10)结合其他漏洞,如CSRF漏洞,实施进一步作恶; (11)提升用户权限,包括进一步渗透网站; (12)传播跨站脚本蠕虫等; 三、过滤器配置 web.xml配置 XssFilter com.xxx.Filter.XssFilter XssFilter /*
©️2020 CSDN 皮肤主题: 博客之星2020 设计师:CY__ 返回首页

打赏

琦彦

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值