XSS跨站脚本攻击
跨站脚本攻击(Cross Site Script为了区别于CSS简称为XSS)指的是恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意用户的特殊目的。
类别:
常见的 XSS 攻击有三种:反射型、DOM-based 型、存储型。 其中反射型、DOM-based 型可以归类为非持久型 XSS 攻击,存储型归类为持久型 XSS 攻击。
1.反射型
反射型 XSS 一般是攻击者通过特定手法(如电子邮件),诱使用户去访问一个包含恶意代码的 URL,当受害者点击这些专门设计的链接的时候,恶意代码会直接在受害者主机上的浏览器执行。
对于访问者而言是一次性的,具体表现在我们把我们的恶意脚本通过 URL 的方式传递给了服务器,而服务器则只是不加处理的把脚本“反射”回访问者的浏览器而使访问者的浏览器执行相应的脚本。反射型 XSS 的触发有后端的参与,要避免反射性 XSS,必须需要后端的协调,后端解析前端的数据时首先做相关的字串检测和转义处理。
此类 XSS 通常出现在网站的搜索栏、用户登录口等地方,常用来窃取客户端 Cookies 或进行钓鱼欺骗。
2.DOM-based 型
客户端的脚本程序可以动态地检查和修改页面内容,而不依赖于服务器端的数据。例如客户端如从 URL 中提取数据并在本地执行,如果用户在客户端输入的数据包含了恶意的 JavaScript 脚本,而这些脚本没有经过适当的过滤和消毒,那么应用程序就可能受到 DOM-based XSS 攻击。需要特别注意以下的用户输入源 document.URL、 location.hash、 location.search、 document.referrer 等。
3.存储型
攻击者事先将恶意代码上传或储存到漏洞服务器中,只要受害者浏览包含此恶意代码的页面就会执行恶意代码。这就意味着只要访问了这个页面的访客,都有可能会执行这段恶意脚本,因此储存型XSS的危害会更大。
存储型 XSS 一般出现在网站留言、评论、博客日志等交互处,恶意脚本存储到客户端或者服务端的数据库中。
解决方案:参考:https://blog.csdn.net/Ideality_hunter/article/details/80621138
方法一:使用过滤器
1.NewXssFilter
1 public class NewXssFilter implements Filter { 2 3 FilterConfig filterConfig = null; 4 5 @Override 6 public void destroy() { 7 this.filterConfig = null; 8 } 9 10 @Override 11 public void doFilter(ServletRequest request, ServletResponse response, 12 FilterChain chain) throws IOException, ServletException { 13 String path = ((HttpServletRequest) request).getContextPath(); 14 // String basePath = request.getScheme() + "://" + request.getServerName() 15 // + ":" + request.getServerPort() + path + "/"; 16 17 String basePath = request.getServerName(); 18 19 20 21 // HTTP 头设置 Referer过滤 22 String referer = ((HttpServletRequest) request).getHeader("Referer"); // REFRESH 23 24 NewXssHttpServletRequestWrapper xssRequest = null; 25 26 try{ 27 // if (referer != null && referer.indexOf(basePath) < 0) { 28 // ((HttpServletRequest) request).getRequestDispatcher(((HttpServletRequest) request).getRequestURI()).forward(((HttpServletRequest) request), response); 29 // System.out.println("referer不为空,referer >>>>>>>>>>>>>> " + referer); 30 // } 31 32 xssRequest = new NewXssHttpServletRequestWrapper((HttpServletRequest) request); 33 chain.doFilter(xssRequest, response); 34 } 35 catch(Exception ex){ 36 ex.printStackTrace(); 37 } 38 // NewXssHttpServletRequestWrapper xssRequest = new NewXssHttpServletRequestWrapper((HttpServletRequest) request); 39 40 } 41 42 @Override 43 public void init(FilterConfig filterConfig) throws ServletException { 44 this.filterConfig = filterConfig; 45 } 46 47 }
2.web.xml
1 <filter> 2 <filter-name>XssSqlFilter</filter-name> 3 <filter-class>com.wx.business.common.xssprotect.NewXssFilter</filter-class> 4 </filter>
3.NewXssHttpServletRequestWrapper
1 public class NewXssHttpServletRequestWrapper extends HttpServletRequestWrapper { 2 3 HttpServletRequest orgRequest = null; 4 5 public NewXssHttpServletRequestWrapper(HttpServletRequest request) { 6 super(request); 7 orgRequest = request; 8 } 9 10 /** 11 * 覆盖getParameter方法,将参数名和参数值都做xss过滤。<br/> 12 * 如果需要获得原始的值,则通过super.getParameterValues(name)来获取<br/> 13 * getParameterNames,getParameterValues和getParameterMap也可能需要覆盖 14 */ 15 @Override 16 public String getParameter(String name) { 17 // System.out.println("NewXssFilter处理前的 Value = " + super.getParameterValues(name)); 18 19 String value = super.getParameter(xssEncode(name)); 20 if (value != null) { 21 value = xssEncode(value); 22 } 23 24 // System.out.println("NewXssFilter处理后的 Value = " + value); 25 26 return value; 27 } 28 29 @Override 30 public Map getParameterMap() { 31 Map returnMap = new HashMap(); 32 Map map = super.getParameterMap(); 33 34 Iterator entries = map.entrySet().iterator(); 35 Map.Entry entry; 36 String name = ""; 37 while (entries.hasNext()) { 38 entry = (Map.Entry) entries.next(); 39 name = xssEncode((String) entry.getKey()); 40 41 // System.out.println(name); 42 43 Object valueObj = entry.getValue(); 44 if (null == valueObj) { 45 returnMap.put(name, valueObj); 46 } else if (valueObj instanceof String[]) { 47 String[] values = (String[]) valueObj; 48 String[] escapeVal = new String[values.length]; 49 for (int i = 0; i < values.length; i++) { 50 escapeVal[i] = xssEncode(values[i]); 51 } 52 returnMap.put(name, escapeVal); 53 } else { 54 returnMap.put(name, valueObj); 55 } 56 57 } 58 return returnMap; 59 } 60 61 /** 62 * 覆盖getHeader方法,将参数名和参数值都做xss过滤。<br/> 63 * 如果需要获得原始的值,则通过super.getHeaders(name)来获取<br/> 64 * getHeaderNames 也可能需要覆盖 65 */ 66 @Override 67 public String getHeader(String name) { 68 69 String value = super.getHeader(xssEncode(name)); 70 if (value != null) { 71 value = xssEncode(value); 72 } 73 return value; 74 } 75 76 /** 77 * 将容易引起xss漏洞的半角字符直接替换成全角字符 78 * 79 * @param s 80 * @return 81 */ 82 public String xssEncode(String s) { 83 if ((s == null) || s.isEmpty()) { 84 return s; 85 } 86 87 String result = stripXSS(s); 88 if (null != result) { 89 result = escape(result); 90 } 91 92 return result; 93 } 94 95 public String escape(String s) { 96 StringBuilder sb = new StringBuilder(s.length() + 16); 97 for (int i = 0; i < s.length(); i++) 98 { 99 char c = s.charAt(i); 100 switch (c) 101 { 102 case '>': 103 sb.append('>');// 全角大于号 104 break; 105 case '<': 106 sb.append('<');// 全角小于号 107 break; 108 /*case '\'': 109 sb.append('‘');// 全角单引号 110 break; 111 case '\"': 112 sb.append('“');// 全角双引号 113 break; 114 case '\\': 115 sb.append('\');// 全角斜线 116 break; 117 case '%': 118 sb.append('%'); // 全角冒号 119 break;*/ 120 default: 121 sb.append(c); 122 break; 123 } 124 125 } 126 return sb.toString(); 127 //return s; 128 } 129 130 private String stripXSS(String value) { 131 if (value != null) { 132 // NOTE: It's highly recommended to use the ESAPI library and 133 // uncomment the following line to 134 // avoid encoded attacks. 135 // value = ESAPI.encoder().canonicalize(value); 136 // Avoid null characters 137 value = value.replaceAll("", ""); 138 // Avoid anything between script tags 139 Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE); 140 value = scriptPattern.matcher(value).replaceAll(""); 141 // Avoid anything in a src='...' type of expression 142 scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE 143 | Pattern.MULTILINE | Pattern.DOTALL); 144 value = scriptPattern.matcher(value).replaceAll(""); 145 scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE 146 | Pattern.MULTILINE | Pattern.DOTALL); 147 value = scriptPattern.matcher(value).replaceAll(""); 148 // Remove any lonesome </script> tag 149 scriptPattern = Pattern.compile("</script>", Pattern.CASE_INSENSITIVE); 150 value = scriptPattern.matcher(value).replaceAll(""); 151 // Remove any lonesome <script ...> tag 152 scriptPattern = Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE 153 | Pattern.DOTALL); 154 value = scriptPattern.matcher(value).replaceAll(""); 155 // Avoid eval(...) expressions 156 scriptPattern = Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE 157 | Pattern.DOTALL); 158 value = scriptPattern.matcher(value).replaceAll(""); 159 // Avoid expression(...) expressions 160 scriptPattern = Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE 161 | Pattern.DOTALL); 162 value = scriptPattern.matcher(value).replaceAll(""); 163 // Avoid javascript:... expressions 164 scriptPattern = Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE); 165 value = scriptPattern.matcher(value).replaceAll(""); 166 // Avoid vbscript:... expressions 167 scriptPattern = Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE); 168 value = scriptPattern.matcher(value).replaceAll(""); 169 // Avoid onload= expressions 170 scriptPattern = Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE 171 | Pattern.DOTALL); 172 value = scriptPattern.matcher(value).replaceAll(""); 173 174 scriptPattern = Pattern.compile("<iframe>(.*?)</iframe>", Pattern.CASE_INSENSITIVE); 175 value = scriptPattern.matcher(value).replaceAll(""); 176 177 scriptPattern = Pattern.compile("</iframe>", Pattern.CASE_INSENSITIVE); 178 value = scriptPattern.matcher(value).replaceAll(""); 179 // Remove any lonesome <script ...> tag 180 scriptPattern = Pattern.compile("<iframe(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE 181 | Pattern.DOTALL); 182 value = scriptPattern.matcher(value).replaceAll(""); 183 } 184 return value; 185 } 186 187 /** 188 * 获取最原始的request 189 * 190 * @return 191 */ 192 public HttpServletRequest getOrgRequest() { 193 return orgRequest; 194 } 195 196 /** 197 * 获取最原始的request的静态方法 198 * 199 * @return 200 */ 201 public static HttpServletRequest getOrgRequest(HttpServletRequest req) { 202 if (req instanceof NewXssHttpServletRequestWrapper) { 203 return ((NewXssHttpServletRequestWrapper) req).getOrgRequest(); 204 } 205 206 return req; 207 } 208 209 }
方法二:jfinal实现
参考:https://blog.csdn.net/zzzgd_666/article/details/80356266