JAVA覆写Request过滤XSS跨站脚本攻击
注:本文非本人原著。
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 }
为人:谦逊、激情、博学、审问、慎思、明辨、 笃行
学问:纸上得来终觉浅,绝知此事要躬行
为事:工欲善其事,必先利其器。
态度:道阻且长,行则将至;行而不辍,未来可期
.....................................................................
------- 桃之夭夭,灼灼其华。之子于归,宜其室家。 ---------------
------- 桃之夭夭,有蕡其实。之子于归,宜其家室。 ---------------
------- 桃之夭夭,其叶蓁蓁。之子于归,宜其家人。 ---------------
=====================================================================
* 博客文章部分截图及内容来自于学习的书本及相应培训课程以及网络其他博客,仅做学习讨论之用,不做商业用途。
* 如有侵权,马上联系我,我立马删除对应链接。 * @author Alan -liu * @Email no008@foxmail.com
转载请标注出处! ✧*꧁一品堂.技术学习笔记꧂*✧. ---> https://www.cnblogs.com/ios9/
学问:纸上得来终觉浅,绝知此事要躬行
为事:工欲善其事,必先利其器。
态度:道阻且长,行则将至;行而不辍,未来可期
.....................................................................
------- 桃之夭夭,灼灼其华。之子于归,宜其室家。 ---------------
------- 桃之夭夭,有蕡其实。之子于归,宜其家室。 ---------------
------- 桃之夭夭,其叶蓁蓁。之子于归,宜其家人。 ---------------
=====================================================================
* 博客文章部分截图及内容来自于学习的书本及相应培训课程以及网络其他博客,仅做学习讨论之用,不做商业用途。
* 如有侵权,马上联系我,我立马删除对应链接。 * @author Alan -liu * @Email no008@foxmail.com
转载请标注出处! ✧*꧁一品堂.技术学习笔记꧂*✧. ---> https://www.cnblogs.com/ios9/