注:本文非本人原著。
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 }