1. 程式人生 > >JAVA覆寫Request過濾XSS跨站腳本攻擊

JAVA覆寫Request過濾XSS跨站腳本攻擊

getpara header term implement nbsp super exceptio stream elements

註:本文非本人原著。

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跨站腳本攻擊