本文共 5791 字,大约阅读时间需要 19 分钟。
(1)在web.xml中配置这样一个过滤器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <!-- 过滤XSS --> < filter > < filter-name >xssFilter</ filter-name > < filter-class >cn.zifangsky.filter.XSSFilter</ filter-class > < init-param > < param-name >exclude</ param-name > < param-value >/;/scripts/*;/styles/*;/images/*</ param-value > </ init-param > </ filter > < filter-mapping > < filter-name >xssFilter</ filter-name > < url-pattern >*.html</ url-pattern > <!-- 直接从客户端过来的请求以及通过forward过来的请求都要经过该过滤器 --> < dispatcher >REQUEST</ dispatcher > < dispatcher >FORWARD</ dispatcher > </ filter-mapping > |
(2)过滤器XSSFilter.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | package cn.zifangsky.filter; import java.io.IOException; import java.util.Enumeration; import java.util.Map; import java.util.Vector; import java.util.regex.Pattern; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringEscapeUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; public class XSSFilter extends OncePerRequestFilter { private String exclude = null ; //不需要过滤的路径集合 private Pattern pattern = null ; //匹配不需要过滤路径的正则表达式 public void setExclude(String exclude) { this .exclude = exclude; pattern = Pattern.compile(getRegStr(exclude)); } /** * XSS过滤 */ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String requestURI = request.getRequestURI(); if (StringUtils.isNotBlank(requestURI)) requestURI = requestURI.replace(request.getContextPath(), "" ); if (pattern.matcher(requestURI).matches()) filterChain.doFilter(request, response); else { EscapeScriptwrapper escapeScriptwrapper = new EscapeScriptwrapper(request); filterChain.doFilter(escapeScriptwrapper, response); } } /** * 将传递进来的不需要过滤得路径集合的字符串格式化成一系列的正则规则 * @param str 不需要过滤的路径集合 * @return 正则表达式规则 * */ private String getRegStr(String str){ if (StringUtils.isNotBlank(str)){ String[] excludes = str.split( ";" ); //以分号进行分割 int length = excludes.length; for ( int i= 0 ;i<length;i++){ String tmpExclude = excludes[i]; //对点、反斜杠和星号进行转义 tmpExclude = tmpExclude.replace( "\\" , "\\\\" ).replace( "." , "\\." ).replace( "*" , ".*" ); tmpExclude = "^" + tmpExclude + "$" ; excludes[i] = tmpExclude; } return StringUtils.join(excludes, "|" ); } return str; } /** * 继承HttpServletRequestWrapper,创建装饰类,以达到修改HttpServletRequest参数的目的 * */ private class EscapeScriptwrapper extends HttpServletRequestWrapper{ private Map<String, String[]> parameterMap; //所有参数的Map集合 public EscapeScriptwrapper(HttpServletRequest request) { super (request); parameterMap = request.getParameterMap(); } //重写几个HttpServletRequestWrapper中的方法 /** * 获取所有参数名 * @return 返回所有参数名 * */ @Override public Enumeration<String> getParameterNames() { Vector<String> vector = new Vector<String>(parameterMap.keySet()); return vector.elements(); } /** * 获取指定参数名的值,如果有重复的参数名,则返回第一个的值 * 接收一般变量 ,如text类型 * * @param name 指定参数名 * @return 指定参数名的值 * */ @Override public String getParameter(String name) { String[] results = parameterMap.get(name); if (results == null || results.length <= 0 ) return null ; else { return escapeXSS(results[ 0 ]); } } /** * 获取指定参数名的所有值的数组,如:checkbox的所有数据 * 接收数组变量 ,如checkobx类型 * */ @Override public String[] getParameterValues(String name) { String[] results = parameterMap.get(name); if (results == null || results.length <= 0 ) return null ; else { int length = results.length; for ( int i= 0 ;i<length;i++){ results[i] = escapeXSS(results[i]); } return results; } } /** * 过滤字符串中的js脚本 * 解码:StringEscapeUtils.unescapeXml(escapedStr) * */ private String escapeXSS(String str){ // return StringEscapeUtils.escapeXml(StringEscapeUtils.escapeEcmaScript(str)); return StringEscapeUtils.escapeXml(str); } } } |
当然,我这里主要说的是如何将在web.xml中配置的不需要过滤的路径集合转换为正则匹配模式,如果把相关代码抽出来就是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; public class Demo3 { private static String getRegStr(String str){ if (StringUtils.isNotBlank(str)){ String[] excludes = str.split( ";" ); //以分号进行分割 int length = excludes.length; for ( int i= 0 ;i<length;i++){ String tmpExclude = excludes[i]; //对点、反斜杠和星号进行转义 tmpExclude = tmpExclude.replace( "\\" , "\\\\" ).replace( "." , "\\." ).replace( "*" , ".*" ); tmpExclude = "^" + tmpExclude + "$" ; excludes[i] = tmpExclude; } return StringUtils.join(excludes, "|" ); } return str; } public static void main(String[] args) { String t1 = "/;/scripts/*;/styles/*;/images/*" ; String t2 = "*/js/*;/scripts/*;" ; String t3 = "\\;\\scripts\\*" ; String t4 = "*" ; String t5 = "/pages/*/js/*" ; String t6 = "/page.html/js/*" ; String test = "/pages/scripts/xx.js" ; Pattern pattern = Pattern.compile(Demo3.getRegStr(t1)); if (pattern.matcher(test).matches()){ System.out.println( "该路径不需要过滤" ); // filterChain.doFilter(request, response); } else { System.out.println( "需要过滤处理" ); // EscapeScriptwrapper escapeScriptwrapper = new EscapeScriptwrapper(request); // filterChain.doFilter(escapeScriptwrapper, response); } } } |
代码很简单,因此这里就不多做解释了
本文转自 pangfc 51CTO博客,原文链接:http://blog.51cto.com/983836259/1862603,如需转载请自行联系原作者