注:本文非本人原著。
demo的地址:链接:http://pan.baidu.com/s/1miEmHMo 密码:k5ca
如何过滤Xss跨站脚本攻击,我想,Xss跨站脚本攻击令人为之头疼。为什么呢。
尤其是有富文本编辑器的产品。xss可能出现在http的head,不说别的,新浪多次出现。
xss可以出现在post数据的正文。图片的url。
于是各种Xss横行,如今Xss跨站脚本漏洞的流行程度甚至超过了当年的sql。
那么对于JAVA语言,如何防御呢。
笔者分享一个思路:所有的web项目,所有的参数都是request获得。
不管是json合适xml又或者post表单数据。甚至图片、文件等等都是如此。
那么,如果对request做个手脚。是不是就可以过滤xss了呢。
正是如此。
如下分享代码。网络上也有类似的过滤器,但不如笔者这份强悍。
1 2 package com.blog.web.base.wrapper; 3 4 import java.io.ByteArrayInputStream; 5 import java.io.ByteArrayOutputStream; 6 import java.io.IOException; 7 import java.io.InputStream; 8 import java.util.ArrayList; 9 import java.util.Enumeration; 10 import java.util.HashMap; 11 import java.util.List; 12 import java.util.Map; 13 import java.util.regex.Pattern; 14 15 import javax.servlet.ServletInputStream; 16 import javax.servlet.http.HttpServletRequest; 17 import javax.servlet.http.HttpServletRequestWrapper; 18 19 /** 20 * 覆写Request方法,过滤XSS恶意脚本 21 * 22 * @author WebSOS 23 * @time 2015-06-09 24 */ 25 public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { 26 27 HttpServletRequest orgRequest = null; 28 29 public XssHttpServletRequestWrapper(HttpServletRequest request) { 30 super(request); 31 orgRequest = request; 32 } 33 34 /** 35 * 覆盖getParameter方法,将参数名和参数值都做xss过滤。 36 */ 37 @Override 38 public String getParameter(String name) { 39 String value = super.getParameter(name); 40 if (value != null) { 41 value = xssEncode(value); 42 } 43 return value; 44 } 45 46 /** 47 * 覆盖getHeader方法,将参数名和参数值都做xss过滤。 避免部分head操作引发的xss 48 */ 49 @Override 50 public String getHeader(String name) { 51 52 String value = super.getHeader(name); 53 if (value != null) { 54 value = xssEncode(value); 55 } 56 return value; 57 } 58 59 /** 60 * 覆盖getHeaderNames方法,避免穷举head参数名引发的xss 61 */ 62 @Override 63 public Enumeration<String> getHeaderNames() { 64 65 Enumeration<String> headNames = super.getHeaderNames(); 66 String value = null; 67 List<String> values = new ArrayList<String>(); 68 while (headNames.hasMoreElements()) { 69 try { 70 value = (String) headNames.nextElement(); 71 if (value == null) { 72 continue; 73 } 74 value = xssEncode(value); 75 values.add(value); 76 } catch (Exception e) { 77 e.printStackTrace(); 78 } 79 } 80 if (values.isEmpty()) { 81 return null; 82 } 83 headNames = new XssEnumerator(0, values.size(), values); 84 return headNames; 85 } 86 87 /** 88 * 覆盖getParameterNames方法,避免穷举参数名引发的xss 89 */ 90 @Override 91 public Enumeration<String> getParameterNames() { 92 Enumeration<String> paraNames = super.getParameterNames(); 93 if (paraNames == null) { 94 return null; 95 } 96 String value = null; 97 List<String> values = new ArrayList<String>(); 98 while (paraNames.hasMoreElements()) { 99 try { 100 value = (String) paraNames.nextElement(); 101 if (value == null) { 102 continue; 103 } 104 value = xssEncode(value); 105 values.add(value); 106 } catch (Exception e) { 107 e.printStackTrace(); 108 } 109 } 110 if (values.isEmpty()) { 111 return null; 112 } 113 paraNames = new XssEnumerator(0, values.size(), values); 114 return paraNames; 115 } 116 117 /** 118 * 覆盖getParameterMap方法,避免穷举参数名或值引发的xss 119 */ 120 @Override 121 public Map<String, String[]> getParameterMap() { 122 Map<String, String[]> map = super.getParameterMap(); 123 Map<String, String[]> paraMap = new HashMap<String, String[]>(); 124 if (map == null) { 125 return null; 126 } 127 String[] values = null; 128 for (String key : map.keySet()) { 129 try { 130 values = map.get(key); 131 if (values != null) { 132 for (int i = 0; i < values.length; i++) { 133 try { 134 values[i] = xssEncode(values[i]); 135 } catch (Exception e) { 136 e.printStackTrace(); 137 } 138 } 139 } 140 paraMap.put(xssEncode(key), values); 141 } catch (Exception e) { 142 e.printStackTrace(); 143 } 144 } 145 return paraMap; 146 } 147 148 /** 149 * 覆盖getInputStream方法,避免上传文件出现的xss或脚本代码 150 */ 151 @Override 152 public ServletInputStream getInputStream() throws IOException { 153 XSSServletInputStream xssServletInputStream = new XSSServletInputStream(); 154 ServletInputStream inputStream = orgRequest.getInputStream(); 155 156 ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); 157 try { 158 int ch; 159 while ((ch = inputStream.read()) != -1) { 160 byteStream.write(ch); 161 } 162 } finally { 163 inputStream.close(); 164 } 165 xssServletInputStream.stream = new ByteArrayInputStream(xssEncode( 166 new String(byteStream.toByteArray(), "iso-8859-1")).getBytes( 167 "iso-8859-1")); 168 return xssServletInputStream; 169 } 170 171 /** 172 * 将容易引起xss漏洞的字符清理掉 173 * 174 * @param s 175 * @return 176 */ 177 private static String xssEncode(String value) { 178 if (value != null) { 179 /* 180 * value = value.replace("<", "<"); value = value.replace(">", 181 * ">"); 182 */ 183 // 如需开启富文本请撤销以下注释 184 185 Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", 186 Pattern.CASE_INSENSITIVE); 187 value = scriptPattern.matcher(value).replaceAll(""); 188 189 scriptPattern = Pattern.compile("</script>", 190 Pattern.CASE_INSENSITIVE); 191 value = scriptPattern.matcher(value).replaceAll(""); 192 193 scriptPattern = Pattern.compile("<img.*?on.*?=.*?>", 194 Pattern.CASE_INSENSITIVE); 195 value = scriptPattern.matcher(value).replaceAll(""); 196 197 scriptPattern = Pattern.compile("<script(.*?)>", 198 Pattern.CASE_INSENSITIVE | Pattern.MULTILINE 199 | Pattern.DOTALL); 200 value = scriptPattern.matcher(value).replaceAll(""); 201 202 scriptPattern = Pattern.compile("eval\((.*?)\)", 203 Pattern.CASE_INSENSITIVE | Pattern.MULTILINE 204 | Pattern.DOTALL); 205 value = scriptPattern.matcher(value).replaceAll(""); 206 207 scriptPattern = Pattern.compile("expression\((.*?)\)", 208 Pattern.CASE_INSENSITIVE | Pattern.MULTILINE 209 | Pattern.DOTALL); 210 value = scriptPattern.matcher(value).replaceAll(""); 211 212 scriptPattern = Pattern.compile("expression\((.*?)\)", 213 Pattern.CASE_INSENSITIVE | Pattern.MULTILINE 214 | Pattern.DOTALL); 215 value = scriptPattern.matcher(value).replaceAll(""); 216 217 scriptPattern = Pattern.compile("javascript:", 218 Pattern.CASE_INSENSITIVE); 219 value = scriptPattern.matcher(value).replaceAll(""); 220 221 scriptPattern = Pattern.compile("vbscript:", 222 Pattern.CASE_INSENSITIVE); 223 value = scriptPattern.matcher(value).replaceAll(""); 224 225 scriptPattern = Pattern.compile("onload(.*?)=", 226 Pattern.CASE_INSENSITIVE | Pattern.MULTILINE 227 | Pattern.DOTALL); 228 value = scriptPattern.matcher(value).replaceAll(""); 229 230 scriptPattern = Pattern.compile("<%.*?java.*?%>", Pattern.CASE_INSENSITIVE 231 | Pattern.MULTILINE | Pattern.DOTALL); 232 value = scriptPattern.matcher(value).replaceAll(""); 233 234 scriptPattern = Pattern.compile("<jsp:.*?>.*?</jsp:.*?>", 235 Pattern.CASE_INSENSITIVE | Pattern.MULTILINE 236 | Pattern.DOTALL); 237 value = scriptPattern.matcher(value).replaceAll(""); 238 239 scriptPattern = Pattern.compile("<meta.*?>", 240 Pattern.CASE_INSENSITIVE | Pattern.MULTILINE 241 | Pattern.DOTALL); 242 value = scriptPattern.matcher(value).replaceAll(""); 243 244 } 245 return value; 246 } 247 248 /** 249 * 获取最原始的request 250 * 251 * @return 252 */ 253 public HttpServletRequest getOrgRequest() { 254 255 return orgRequest; 256 } 257 258 /** 259 * 获取最原始的request的静态方法 260 * 261 * @return 262 */ 263 public static HttpServletRequest getOrgRequest(HttpServletRequest req) { 264 if (req instanceof XssHttpServletRequestWrapper) { 265 return ((XssHttpServletRequestWrapper) req).getOrgRequest(); 266 } 267 268 return req; 269 } 270 271 private class XSSServletInputStream extends ServletInputStream { 272 private InputStream stream; 273 274 @Override 275 public int read() throws IOException { 276 return stream.read(); 277 } 278 } 279 280 private class XssEnumerator implements Enumeration<String> { 281 int count; // 计数器 282 int length; // 存储的数组的长度 283 List<String> dataArray; // 存储数据数组的引用 284 285 XssEnumerator(int count, int length, List<String> dataArray) { 286 this.count = count; 287 this.length = length; 288 this.dataArray = dataArray; 289 290 } 291 292 public boolean hasMoreElements() { 293 return (count < length); 294 } 295 296 public String nextElement() { 297 return dataArray.get(count++); 298 } 299 } 300 301 public static void main(String[] args) { 302 Enumeration<String> paraNames = (Enumeration<String>) new ArrayList(); 303 } 304 }