springmvc使用过滤器filter实现过滤XSS,SQL脚本等功能

springmvc使用过滤器filter实现过滤XSS,SQL脚本等功能,然后在初始化init方法加载需要过滤的XSS,SQL脚本配置,

package com.csair.csm.web.filter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

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 com.csair.csm.util.ParamRequestWrapper;

public class XssFilter implements Filter {

  private String interceptStr = null;
  private List<String> interceptArr = new ArrayList<String>();
  private String validateStr = null;
  private List<String> validateArr = new ArrayList<String>();
  private String sqlInterceptArrStr = null;
  private List<String> sqlInterceptArr = new ArrayList<String>();

  @Override
  public void init(FilterConfig filterConfig) throws ServletException {
    interceptStr = filterConfig.getInitParameter("intercept");
    interceptArr = Arrays.asList(interceptStr.split(";"));


    sqlInterceptArrStr = filterConfig.getInitParameter("sqlValidate");
    sqlInterceptArr = Arrays.asList(sqlInterceptArrStr.split("\\|"));

    validateStr = filterConfig.getInitParameter("validate");
    validateArr = Arrays.asList(validateStr.split("\\|"));
    for (String item : validateArr) {
      ParamRequestWrapper.patternArr.add(Pattern.compile(item.toLowerCase()));
    }
    ParamRequestWrapper.validateArr = this.validateArr;
    ParamRequestWrapper.interceptArr = this.interceptArr;
    ParamRequestWrapper.sqlInterceptArr = this.sqlInterceptArr;
  }

  /**
   * 
   * @see javax.servlet.Filter#destroy()
   */
  @Override
  public void destroy() {}

  /**
   * @param arg0
   * @param arg1
   * @param arg2
   * @throws IOException
   * @throws ServletException
   * @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 {
    HttpServletRequest servletRequest = (HttpServletRequest) request;
    // 解决post中文乱码问题
    request.setCharacterEncoding("UTF-8");
    response.setCharacterEncoding("UTF-8");

    chain.doFilter(new ParamRequestWrapper(servletRequest), response);
  }
}

ParamRequestWrapper.java类如下 

package com.csair.csm.util;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

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

public class ParamRequestWrapper extends HttpServletRequestWrapper {

  public static List<Pattern> patternArr = new ArrayList<Pattern>();

  public static List<String> validateArr = new ArrayList<String>();

  public static List<String> sqlInterceptArr = new ArrayList<String>();

  public static List<String> interceptArr = new ArrayList<String>();

  private HttpServletRequest request;
  private final byte[] body; // 报文

  public ParamRequestWrapper(HttpServletRequest request) throws IOException {
    super(request);
    this.request = request;
    body = readBytes(request.getInputStream());
  }

  private byte[] readBytes(InputStream in) throws IOException {
    BufferedInputStream bufin = new BufferedInputStream(in);
    int buffSize = 1024;
    ByteArrayOutputStream out = new ByteArrayOutputStream(buffSize);

    byte[] temp = new byte[buffSize];
    int size = 0;
    while ((size = bufin.read(temp)) != -1) {
      out.write(temp, 0, size);
    }
    bufin.close();
    byte[] content = out.toByteArray();
    return content;
  }

  @Override
  public ServletInputStream getInputStream() throws IOException {
    final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);
    ServletInputStream servletInputStream = new ServletInputStream() {
      public int read() throws IOException {
        return byteArrayInputStream.read();
      }
    };
    return servletInputStream;
  }

  private String format(String name) {
    String value = replaceParams(name);
    if (!this.request.getMethod().equals("GET")) {// 判断是否是get请求方式
      return value;
    }
    String result = null;
    try {
      result = new String(value.getBytes("utf-8"), this.request.getCharacterEncoding());
    } catch (UnsupportedEncodingException e) {
      e.printStackTrace();
    }
    return result;
  }

  public boolean checkIsIntercept() {
    String url = request.getRequestURL().toString();
    boolean flag = false;
    for (String item : interceptArr) {
      if (url.contains(item)) {
        flag = true;
        break;
      }

    }
    return flag;
  }

  public String replaceParams(String value) {
    String formatStr = XSSUtil.escape(value);
    if (checkIsIntercept()) {
      formatStr = formatStr.replaceAll("\"", "&quot;");
    }
    for (String item : validateArr) {
      Matcher matcher = WebUtil.getRegexNormalMatcher(item, formatStr);
      formatStr = matcher.replaceAll("");
    }
    return formatStr;
  }

  /**
   * 
   * @param name
   * @return
   */
  public Object getAttribute(String name) {
    Object value = super.getAttribute(name);
    if (value instanceof String) {
      value = format(String.valueOf(value));
    }
    return value;
  }

  /**
   * 重写getParameter方法
   * 
   * @param name
   * @return
   */
  public String getParameter(String name) {
    String value = super.getParameter(name);
    if (value == null)
      return null;
    return format(value);
  }

  /**
   * 
   * @param name
   * @return
   */
  public String[] getParameterValues(String name) {
    String[] values = super.getParameterValues(name);
    if (values != null) {
      for (int i = 0; i < values.length; i++) {
        values[i] = format(values[i]);
      }
    }
    return values;
  }

  /**
   * @return
   */
  public Map<String, String[]> getParameterMap() {
    Map<String, String[]> paramMap = (Map<String, String[]>) super.getParameterMap();
    Map<String, String[]> resultMap = new HashMap<String, String[]>();

    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]);
        }
      }
      resultMap.put(replaceParams(entry.getKey()), values);
    }
    return resultMap;
  }

}

如果我们的代码程序是用流来接收参数对象,以上的参数过滤封装并不会生效,解决方案,可以在过滤器获取流的时候,作处理,代码如下

public class WrapperRequestBody extends HttpServletRequestWrapper {

  public static List<Pattern> patternArr = new ArrayList<Pattern>();

  public static List<String> validateArr = new ArrayList<String>();

  private final String body;

  public WrapperRequestBody(HttpServletRequest request) throws IOException {
    super(request);
    StringBuilder stringBuilder = new StringBuilder();
    BufferedReader bufferedReader = null;
    try {
      InputStream inputStream = request.getInputStream();
      if (inputStream != null) {
        bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        char[] charBuffer = new char[128];
        int bytesRead = -1;
        while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
          stringBuilder.append(charBuffer, 0, bytesRead);
        }
      } else {
        stringBuilder.append("");
      }
    } catch (IOException ex) {
      throw ex;
    } finally {
      if (bufferedReader != null) {
        try {
          bufferedReader.close();
        } catch (IOException ex) {
          ex.printStackTrace();
        }
      }
    }
    body = format(stringBuilder.toString());
  }

  @Override
  public ServletInputStream getInputStream() throws IOException {
    final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
    ServletInputStream servletInputStream = new ServletInputStream() {
      public int read() throws IOException {
        return byteArrayInputStream.read();
      }
    };
    return servletInputStream;
  }

  @Override
  public BufferedReader getReader() throws IOException {
    return new BufferedReader(new InputStreamReader(this.getInputStream()));
  }

  public String getBody() {
    return this.body;
  }
  
  private String format(String value) {
    if(StringUtils.isEmpty(value)){
      return value;
    }
    return replaceParams(value);
  }

  public String replaceParams(String value) {
    for (String item : validateArr) {
      Matcher matcher = WebUtil.getRegexNormalMatcher(item, value);
      value = matcher.replaceAll("");
    }
    return value;
  }

 

XssUtils.java工具类如下

package com.csair.csm.util;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;



public class XssUtils {

  private static final Logger logger = LoggerFactory.getLogger(XssUtils.class);

  /**
   * 将特殊字符转换为对应的实体引用或字符引用。
   * 
   * @throws IOException
   * @throws IOException
   */
  public static String toHtml(String url, String str) {
    return toHtml2(url, str);
  }

  /**
   * 字符转译,对;单引号,(,) 还有斜杠进行转译成原生字符 例如(&#x3B)+;将变成原生的字符;
   * 
   * @param str
   * @param enc
   * @return 转译后的字符串
   */
  public static String urlDecoderDecode(String str, String enc) {
    str = str.replaceAll("(&#x3B)+;", ";");
    str = str.replaceAll("&#39;", "\'");
    str = str.replaceAll("&#40;", "(");
    str = str.replaceAll("&#41;", ")");
    str = str.replaceAll("&quot;", "\"");
    str = str.replaceAll("&#x2F;", "/");
    try {
      str = URLDecoder.decode(str, enc);
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException("URLDecode转换出错");
    }
    return str;
  }

  /**
   * 将特殊字符转换为对应的实体引用或字符引用。
   */
  private static String toHtml2(String url, String str) {
    if (str == null) {
      return null;
    }
    StringBuffer sb = new StringBuffer();
    boolean hasXssChar = false;
    int len = str.length();
    for (int i = 0; i < len; i++) {
      char c = str.charAt(i);
      switch (c) {
      /*
       * case '\'': sb.append("&#39;"); hasXssChar = true; break; case '\"': sb.append("&quot;");
       * hasXssChar = true; break;
       */
        case '<':
          sb.append("&lt;");
          hasXssChar = true;
          break;
        case '>':
          sb.append("&gt;");
          hasXssChar = true;
          break;
        case '(':
          sb.append("&#40;");
          hasXssChar = true;
          break;
        case ')':
          hasXssChar = true;
          sb.append("&#41;");
          break;
        /*
         * case ';': sb.append("&#x3B;"); hasXssChar = true; break; case '/': sb.append("&#x2F;");
         * hasXssChar = true; break;
         */
        case '\\':
          sb.append("&#92;");
          hasXssChar = true;
          break;
        default:
          sb.append(c);
      }
    }
    if (hasXssChar) {
      logger.debug(url + "进行Xss检查,已进行替换, 原始输入数据为:" + str);
    }
    return sb.toString().replaceAll("script", "").replaceAll("eval\\((.*)\\)", "");
    // return sb.toString();
  }

  @SuppressWarnings("unused")
  private static void logTime(long sTime) {
    if ((System.currentTimeMillis() - sTime) > 100) {
      logger.debug("转义耗时:" + (System.currentTimeMillis() - sTime));
    }
  }

}

WebUtils.java工具类如下

package com.csair.csm.util;

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

public class WebUtil {

  
  public static Matcher getRegexNormalMatcher(String regex, String targetStr) {
    Pattern compile = Pattern.compile( regex ,Pattern.CASE_INSENSITIVE);
    Matcher matcher = compile.matcher(targetStr);
    return matcher;
  }
  
  
}

最后一步,即在WEB.XML配置过滤器指向我们定义的filter,并且配置过滤XSS,SQL脚本的关键字

    <filter>
        <filter-name>xssFilter</filter-name>
        <filter-class>com.csair.csm.web.filter.XssFilter</filter-class>
        	<init-param>
			<param-name>intercept</param-name>
			<param-value>product/search;order/verify;manage/catalog/view;order/myorder;ehome/act</param-value>
		    </init-param>   
        	<init-param>
			<param-name>validate</param-name>
			<param-value><![CDATA[font-family|show|class=|.source|eval|expression|onmouse|onmouseover|javascript|confirm|meta|onblur|window.|document|marquee|location|onfocus|onchange|onclick|onkey|onmousedown|prompt|SYS.TAB|script|alert|iframe|frame|href=|<|>|\\x|%5Cx|\*/|/\*|vbscript:|view-source:|.location|.cookie|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|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]]></param-value>
			</init-param>
			<init-param>
			<param-name>sqlValidate</param-name>
			<param-value><![CDATA[where|or|and|drop|delete]]></param-value>
			</init-param>
    </filter>
	<filter-mapping>
        <filter-name>xssFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

 

转载于:https://my.oschina.net/u/3155476/blog/3056359

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值