跨站腳本攻擊(Cross Site Scripting),為不和層疊樣式表(Cascading Style Sheets, CSS)的縮寫混淆,故將跨站腳本攻擊縮寫為XSS。惡意攻擊者往Web頁面里插入惡意Script(php,js等)代碼,當用戶瀏覽該頁之時,嵌入其中Web里面的Script代碼會被執行,從而達到惡意攻擊用戶的特殊目的。
攻擊實例
下面為一個Input標簽:
<input type="text" value="value"></input>
當用輸入值為" onfocus="alert(document.cookie) 時,input標簽內容變為 <input type="text" value=""onfocus="alert(document.cookie)"></input>
當input中的可以執行的js腳本被存儲到數據庫中。用戶再次取出顯示時。就會取到用戶的cookie。從而得到用戶名和密碼。
(1)添加用戶
(2)數據庫中存儲可執行腳本
(3)編輯用戶(XSS攻擊發生)
攻擊危害
以上獲取用戶名和密碼只是個簡單的xss攻擊,還有跟多的XSS攻擊實例。例如將用戶導航到其他網站,后台掛馬操作等
攻擊預防
原理:主要采用過濾器對請求中的特殊字符進行編碼轉化。從而將可以執行的script代碼變為不可以執行的script腳本存儲到數據庫中。
示例:開發環境采用的SSH框架。所以采用過濾器,注意這里采用裝飾者模式對請求request對象進行了包裝。
注:由於使用了struts2.所以要自定義的裝飾者對象繼承StrutsRequestWrapper類。但是這樣對於上傳文件獲得不到參數。因為上傳文件請求類型為MultiPart
所以包裝對象為原始的請求HttpServletRequestWrapper
具體代碼:
1 public class XssFilter implements Filter { 2 3 public void destroy() { 4 5 } 6 7 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 8 XssStrutsRequestWrapper xssRequest = new XssStrutsRequestWrapper((HttpServletRequest) servletRequest); 9 HttpServletResponse response = (HttpServletResponse)servletResponse; 10 filterChain.doFilter(xssRequest, response); 11 } 12 13 public void init(FilterConfig arg0) throws ServletException { 14 15 } 16 17 }
1 public class XssStrutsRequestWrapper extends HttpServletRequestWrapper{ 2 private HttpServletRequest orgRequest; 3 4 public XssStrutsRequestWrapper(HttpServletRequest request) { 5 super(request); 6 this.orgRequest = request; 7 } 8 /** 9 * 獲取最原始的request 10 * @return 11 */ 12 public HttpServletRequest getOrgRequest() { 13 return orgRequest; 14 } 15 /** 16 * 獲取最原始的request的靜態方法 17 * @return 18 */ 19 public static HttpServletRequest getOrgRequest(HttpServletRequest req) { 20 if (req instanceof XssStrutsRequestWrapper) { 21 return ((XssStrutsRequestWrapper) req).getOrgRequest(); 22 } 23 return req; 24 } 25 /** 26 * 覆蓋getParameter方法,將參數名和參數值都做xss過濾。<br/> 27 * 如果需要獲得原始的值,則通過super.getParameterValues(name)來獲取<br/> 28 * getParameterNames,getParameterValues和getParameterMap也可能需要覆蓋 29 */ 30 @Override 31 public String getParameter(String name) { 32 String value = super.getParameter(xssEncode(name)); 33 if (value != null) { 34 value = xssEncode(value); 35 } 36 return value; 37 } 38 39 /** 40 * 覆蓋getHeader方法,將參數名和參數值都做xss過濾。<br/> 41 * 如果需要獲得原始的值,則通過super.getHeaders(name)來獲取<br/> 42 * getHeaderNames 也可能需要覆蓋 43 */ 44 @Override 45 public String getHeader(String name) { 46 String value = super.getHeader(xssEncode(name)); 47 if (value != null) { 48 value = xssEncode(value); 49 } 50 return value; 51 } 52 /** 53 * 覆蓋getParamterMap方法, 54 */ 55 @Override 56 @SuppressWarnings("unchecked") 57 public Map<String, String[]> getParameterMap() { 58 Map<String, String[]> paramMap = super.getParameterMap(); 59 Set<String> keySet = paramMap.keySet(); 60 for (Iterator iterator = keySet.iterator(); iterator.hasNext();) { 61 String key = (String) iterator.next(); 62 String[] str = paramMap.get(key); 63 for(int i=0; i<str.length; i++) { 64 // 對參數值進行編碼過濾 65 str[i] = xssEncode(str[i]); 66 } 67 } 68 return paramMap ; 69 } 70 public String xssEncode(String source){ 71 if (source == null) { 72 return ""; 73 } 74 String html = ""; 75 StringBuffer buffer = new StringBuffer(); 76 for (int i = 0; i < source.length(); i++) { 77 char c = source.charAt(i); 78 switch (c) { 79 case '<': 80 //buffer.append("<"); 81 buffer.append("<"); 82 break; 83 case '>': 84 //buffer.append(">"); 85 buffer.append(">"); 86 break; 87 case '&': 88 //buffer.append("&"); 89 buffer.append("&"); 90 break; 91 case '"': 92 //buffer.append("""); 93 buffer.append("""); 94 break; 95 default: 96 buffer.append(c); 97 } 98 } 99 html = buffer.toString(); 100 return html; 101 } 102 103 }
這里編碼實現主要是xssEncode(String source)方法。XssStrutsRequestWrapper必須重寫getParameterMap()方法。並調用xssEncode(String source)編碼。
結果:
數據中內容將英文的“變為全角" 。從而將可以執行的js腳本並未不可執行的腳本存儲在數據庫中。