SpringMvc如何进行XSS攻击过滤

随着web飞速的发展,XSS漏洞已经不容忽视,简单介绍一下XSS漏洞, 只要有用户输入的地方,就会出现XSS漏洞,例如在发表一篇帖子的时候,在其中加入脚本。
比如我在表单文本框中,输入

 <script>alert(233)</script>

那么当这条消息存到数据库,再次在页面上访问获取数据的时候,就会弹出弹窗.
很多网站为了避免XSS的攻击,对用户的输入都采取了过滤,最常见的就是对<>转换成<以及>,经过转换以后<>虽然可在正确显示在页面上,但是已经不能构成代码语句了

前不久我写了一个JFinal的XSS,这个是在JBoot上面用到的

JFinal如何进行XSS攻击

现在又用到SpringMvc, 自然又得重新写一份SpringMvc的过滤方法

主要思路

  1. 建一个过滤器,过滤来自页面的请求
  2. 在过滤器中,将原本的request替换成我们自己包装好的request
  3. 我们写一个request的装饰类,里面重写获取参数的方法,对参数进行转义和替换

具体代码

1. 过滤器
package com.zgd.admin.common.filter;

import java.io.IOException;

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.HttpServletResponse;

import org.springframework.web.filter.OncePerRequestFilter;


/**
 * 处理xss攻击的过滤器
 * @author Admin
 * 2018年5月23日16:12:26
 */
public class RequestFilter extends OncePerRequestFilter {


	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		// 将request通过自定义的装饰类进行装饰
		XssRequestWrapper xssRequest = new XssRequestWrapper((HttpServletRequest) request);		
		filterChain.doFilter(xssRequest, response);
	}
	
}

2. reqeust包装类,重写getParameter()等方法,这里面对参数的转义和替换,根据实际需求更改

这里其实可以推荐一些html标签处理的框架

public static void main(String[] args) {
    
    String clean = Jsoup.clean("<a href='www.baidu.com>百度</a><script>alert(2333)</script><font color='red'>红色的</font>哈哈哈", Safelist.basic());
    System.out.println("clean = " + clean); //<a rel="nofollow">红色的哈哈哈</a>
    
    String relaxed = Jsoup.clean("<a href='www.baidu.com>百度</a><script>alert(2333)</script><font color='red'>红色的</font>哈哈哈", Safelist.relaxed());
    System.out.println("relaxed = " + relaxed); //<a>红色的哈哈哈</a>
    
    String simpleText = Jsoup.clean("<a href='www.baidu.com>百度</a><script>alert(2333)</script><font color='red'>红色的</font>哈哈哈", Safelist.simpleText());
    System.out.println("simpleText = " + simpleText); //红色的哈哈哈
  }
  • 正则匹配
package com.zgd.api.gateway.handler;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Logger;
import java.util.regex.Pattern;

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

public class XssRequestWrapper extends HttpServletRequestWrapper {

	private HttpServletRequest request;
	
	public XssRequestWrapper(HttpServletRequest request) {
		super(request);
		this.request = request;
	}
	
	/**
     * 重写getParameter方法
     */
	@Override
	public String getParameter(String name) {
		String value = super.getParameter(name);
        if (value == null) {
        	return null;
        }
        value = format(value);
        return value;
	}
	
	/**
     * 重写getParameterMap
     */
	@Override
	@SuppressWarnings("unchecked")
	public Map<String, String[]> getParameterMap() {
		HashMap<String, String[]> paramMap = (HashMap<String, String[]>) super.getParameterMap();
        paramMap = (HashMap<String, String[]>) paramMap.clone();

        for (Iterator iterator = paramMap.entrySet().iterator(); iterator.hasNext(); ) {
            Map.Entry<String, String[]> entry = (Map.Entry<String, String[]>) iterator.next();
            String [] values = entry.getValue();
            for (int i = 0; i < values.length; i++) {
                if(values[i] instanceof String){
                    values[i] = format(values[i]);
                }
            }
            entry.setValue(values);
        }
        return paramMap;
	}
	
	
	/**
     * 重写getParameterValues
     */
	@Override
	public String[] getParameterValues(String name) {
		 String[] values = super.getParameterValues(name);  
		 int count = values.length;  
	        String[] encodedValues = new String[count];  
	        for (int i = 0; i < count; i++) {  
	            encodedValues[i] = format(values[i]);  
	        }  
        return encodedValues;  
	}
	
	/**
     * 重写getHeader
     */
	@Override
	public String getHeader(String name) {
		// TODO Auto-generated method stub
		return format(super.getHeader(name));
	}
	

	public String filter(String message) {
        if (message == null)
            return (null);
        message = format(message);
        return message;
    }
	
	
	 /**
     *  @desc 统一处理特殊字符的方法,替换掉sql和js的特殊字符
     *  @param name 要替换的字符
     */
    private String format(String name) {
    	return xssEncode(name);
    }
    
    /** 
     * 将容易引起xss & sql漏洞的半角字符直接替换成全角字符 
     *  
     * @param s 
     * @return 
     */  
    private static String xssEncode(String s) {  
        if (s == null || s.isEmpty()) {  
            return s;  
        }else{  
            s = stripXSSAndSql(s);  
        }  
        StringBuilder sb = new StringBuilder(s.length() + 16);  
        for (int i = 0; i < s.length(); i++) {  
            char c = s.charAt(i);  
            switch (c) {  
            case '>':  
                sb.append(">");// 转义大于号  
                break;  
            case '<':  
                sb.append("<");// 转义小于号  
                break;  
//            case '\'':  
//                sb.append("'");// 转义单引号  
//                break;  
//            case '\"':  
//                sb.append(""");// 转义双引号  
//                break;  
//            case '&':  
//                sb.append("&");// 转义&  
//                break;  
//            case '#':  
//                sb.append("#");// 转义#  
//                break;  
            default:  
                sb.append(c);  
                break;  
            }  
        }  
        return sb.toString();  
    }  
    
    
    
    /** 
     *  
     * 防止xss跨脚本攻击(替换,根据实际情况调整) 
     */  
    public static String stripXSSAndSql(String value) {  
        if (value != null) {  
            // NOTE: It's highly recommended to use the ESAPI library and  
            // uncomment the following line to  
            // avoid encoded attacks.  
//             value = ESAPI.encoder().canonicalize(value);  
            // Avoid null characters  
/**         value = value.replaceAll("", "");***/  
            // Avoid anything between script tags  
            Pattern scriptPattern = Pattern.compile("<[\r\n| | ]*script[\r\n| | ]*>(.*?)</[\r\n| | ]*script[\r\n| | ]*>", Pattern.CASE_INSENSITIVE);  
            value = scriptPattern.matcher(value).replaceAll("");  
            // Avoid anything in a src="http://www.yihaomen.com/article/java/..." type of e-xpression  
            scriptPattern = Pattern.compile("src[\r\n| | ]*=[\r\n| | ]*[\\\"|\\\'](.*?)[\\\"|\\\']", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);  
            value = scriptPattern.matcher(value).replaceAll("");  
            // Remove any lonesome </script> tag  
            scriptPattern = Pattern.compile("</[\r\n| | ]*script[\r\n| | ]*>", Pattern.CASE_INSENSITIVE);  
            value = scriptPattern.matcher(value).replaceAll("");  
            // Remove any lonesome <script ...> tag  
            scriptPattern = Pattern.compile("<[\r\n| | ]*script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);  
            value = scriptPattern.matcher(value).replaceAll("");  
            // Avoid eval(...) expressions  
            scriptPattern = Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);  
            value = scriptPattern.matcher(value).replaceAll("");  
            // Avoid e-xpression(...) expressions  
            scriptPattern = Pattern.compile("e-xpression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);  
            value = scriptPattern.matcher(value).replaceAll("");  
            // Avoid javascript:... expressions  
            scriptPattern = Pattern.compile("javascript[\r\n| | ]*:[\r\n| | ]*", Pattern.CASE_INSENSITIVE);  
            value = scriptPattern.matcher(value).replaceAll("");  
            // Avoid vbscript:... expressions  
            scriptPattern = Pattern.compile("vbscript[\r\n| | ]*:[\r\n| | ]*", Pattern.CASE_INSENSITIVE);  
            value = scriptPattern.matcher(value).replaceAll("");  
            // Avoid οnlοad= expressions  
            scriptPattern = Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);  
            value = scriptPattern.matcher(value).replaceAll("");  
        }  
        return value;  
    }  
	

}

3. 在web.xml中把自己写的过滤器,放在合适的地方,可以考虑放在编码过滤器后面
<!-- xss注入过滤器 -->
	<filter>
		<filter-name>xssRequestFilter</filter-name>
		<filter-class>com.zgd.admin.common.filter.RequestFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>xssRequestFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
4. 接下来就可以启动项目看看效果了

我们输入

<script>alert(2333)</script><font color='red'>红色的</font>哈哈哈

结果
这里写图片描述

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值