springmvc使用過濾器filter實現過濾XSS,SQL腳本等功能,而後在初始化init方法加載須要過濾的XSS,SQL腳本配置,javascript
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類以下 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("\"", """); } 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; } }
若是咱們的代碼程序是用流來接收參數對象,以上的參數過濾封裝並不會生效,解決方案,能夠在過濾器獲取流的時候,做處理,代碼以下react
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工具類以下web
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); } /** * 字符轉譯,對;單引號,(,) 還有斜槓進行轉譯成原生字符 例如(;)+;將變成原生的字符; * * @param str * @param enc * @return 轉譯後的字符串 */ public static String urlDecoderDecode(String str, String enc) { str = str.replaceAll("(;)+;", ";"); str = str.replaceAll("'", "\'"); str = str.replaceAll("(", "("); str = str.replaceAll(")", ")"); str = str.replaceAll(""", "\""); str = str.replaceAll("/", "/"); 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("'"); hasXssChar = true; break; case '\"': sb.append("""); * hasXssChar = true; break; */ case '<': sb.append("<"); hasXssChar = true; break; case '>': sb.append(">"); hasXssChar = true; break; case '(': sb.append("("); hasXssChar = true; break; case ')': hasXssChar = true; sb.append(")"); break; /* * case ';': sb.append(";"); hasXssChar = true; break; case '/': sb.append("/"); * hasXssChar = true; break; */ case '\\': sb.append("\"); 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工具類以下spring
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腳本的關鍵字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>