JAVA覆写Request过滤XSS跨站脚本攻击

Posted ✧*꧁一品堂.技术学习笔记꧂*✧.

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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("<", "&lt;"); value = value.replace(">",
181 			 * "&gt;");
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("e­xpression\\((.*?)\\)",
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 }

以上是关于JAVA覆写Request过滤XSS跨站脚本攻击的主要内容,如果未能解决你的问题,请参考以下文章

xss跨站脚步攻击

跨站脚本攻击(XSS)

XSS过滤JAVA过滤器filter 防止常见SQL注入

XSS跨站脚本攻击

php安全字段和防止XSS跨站脚本攻击过滤函数

xss(跨站脚本攻击)