之前由我負責維護的一個項目被檢測出存在可能被XSS攻擊的漏洞。
嚇得我趕緊惡補了下XSS。
XSS,全稱為Cross Site Script,跨站腳本攻擊,是WEB程序中一種常見的漏洞。其主要的攻擊手段是在在利用網站上的可由用戶輸入信息的地方,惡意注入含有攻擊性的腳本,達到攻擊網站或者竊取用戶cookied等隱私信息的目的。
XSS漏洞主要分為兩種類型,一種是Stored XSS, 另一種是反射型 XSS。
第一種舉個簡單的例子就是BBS網站,黑客可以利用留言的功能,發表以下內容:
<script type="text/javascript"> alert("surprise") </script>
對系統而言,它認為這和其他的留言一樣都只是字符串。但是當有用戶訪問到這個頁面時,瀏覽器會把這段留言當成html內容來解析。因此就執行了其中的js腳本。
而反射型 XSS則是利用點擊鏈接或是提交一些內容來達到攻擊的目的。
比如我有以下一個頁面:
<form name="formsearch" method="get"> <div class="form"> <input name="q" type="text" class="search-keyword" id="search-keyword" /> <button type="submit" class="search-submit blue-button">搜索</button> </div> </form>
當用戶在input框中輸入: "<script type="text/javascript"> alert(“surperise”) " 時。他也向瀏覽器插入了自己的JS腳本。
當表單被提交時,輸入的字符串被作為參數放在了URL中,傳到下一個頁面。
當下一個頁面需要顯示這些內容,字符串中包含的攻擊腳本也就被瀏覽器解釋了出來。
當然這段腳本只能在自己的瀏覽器執行,可能沒有什么攻擊性,但是黑客們會想盡辦法偽裝頁面達到攻擊的目的。
總之,XSS攻擊就是想辦法讓你的瀏覽器去執行他的腳本。
那么XSS攻擊該如何方法呢。
既然是通過輸入字符串達到植入腳本的目的,那么我們只要對用戶輸入的字符串進行一個處理就好了。
我們可以利用org.apache.commons.lang3.StringEscapeUtils(注:3.6版本起,用commons-text包下的StringEscapeUtils代替)這個類對輸入的參數進行html轉義。
可以定義一個過濾器,然后轉義HttpServletRequest中的參數值。
代碼如下:
定義攔截器
1 import java.io.IOException; 2 3 import javax.servlet.Filter; 4 import javax.servlet.FilterChain; 5 import javax.servlet.FilterConfig; 6 import javax.servlet.ServletException; 7 import javax.servlet.ServletRequest; 8 import javax.servlet.ServletResponse; 9 import javax.servlet.http.HttpServletRequest; 10 11 public class XSSFilter implements Filter { 12 @Override 13 public void init(FilterConfig filterConfig) throws ServletException { 14 15 } 16 17 @Override 18 public void doFilter(ServletRequest request, ServletResponse response, 19 FilterChain chain) throws IOException, ServletException { 20 chain.doFilter(new XSSHttpServletRequestWrapper((HttpServletRequest) request), response); 21 } 22 23 @Override 24 public void destroy() { 25 26 } 27 28 29 }
由於原生的HttpServletRequest不支持你直接修改參數,因此我們定義了一個包裝類,在獲取參數的時候對參數進行轉義。
1 package com.jspxcms.core.support; 2 3 import javax.servlet.http.HttpServletRequest; 4 import javax.servlet.http.HttpServletRequestWrapper; 5 6 import org.apache.commons.lang3.StringEscapeUtils; 7 8 public class XSSHttpServletRequestWrapper extends HttpServletRequestWrapper { 9 10 public XSSHttpServletRequestWrapper(HttpServletRequest request) { 11 super(request); 12 } 13 14 @Override 15 public String getHeader(String name) { 16 return StringEscapeUtils.escapeHtml4(super.getHeader(name)); 17 } 18 19 @Override 20 public String getQueryString() { 21 return StringEscapeUtils.escapeHtml4(super.getQueryString()); 22 } 23 24 @Override 25 public String getParameter(String name) { 26 return StringEscapeUtils.escapeHtml4(super.getParameter(name)); 27 } 28 29 @Override 30 public String[] getParameterValues(String name) { 31 String[] values = super.getParameterValues(name); 32 if(values != null) { 33 int length = values.length; 34 String[] escapseValues = new String[length]; 35 for(int i = 0; i < length; i++){ 36 escapseValues[i] = "1"; 37 } 38 return escapseValues; 39 } 40 return super.getParameterValues(name); 41 } 42 }
最后我們在web.xml中配置我們的攔截器即可(將XXXX換成類的全限定名)。
1 <filter> 2 <filter-name>XssEscape</filter-name> 3 <filter-class>XXXXX.XSSFilter</filter-class> 4 </filter> 5 <filter-mapping> 6 <filter-name>XssEscape</filter-name> 7 <url-pattern>/*</url-pattern> 8 <dispatcher>REQUEST</dispatcher> 9 </filter-mapping>
簡單的XSS防御就完成了。