什麼是XSS?
XSS(Cross Site Scripting),即跨站腳本攻擊,是一種常見於web application中的計算機安全漏洞。XSS經過在用戶端注入惡意的可運行腳本,若服務器端對用戶輸入不進行處理,直接將用戶輸入輸出到瀏覽器,則瀏覽器將會執行用戶注入的腳本。
例如:有一個input輸入框,要求用戶輸入名字,用戶輸入lily<script>alert("hello world")</script>,服務器接收到用戶的輸入,而且直接將用戶輸入輸出到頁面上,則會有hello world 的alert對話框出現。若是說這是XSS黑客的自娛自樂,那麼盜取用戶信息的XSS就不那麼友好了。若是用戶經過注入腳本,盜取你的用戶信息如cookie的內容,仿冒正經常使用戶,進行相應的操做,則危害會更大。獲取用戶的cookie信息很是簡單,只須要使用js獲取document.cookie,便可以獲得。爲了便於分析,咱們將在用戶輸入名字框中輸入:lily<script>alert(document.cookie)</script>,則你就能夠看到你的cookie信息顯示在alert對話框中了。
XSS的分類
根據XSS形成的影響,能夠將XSS分爲非持久型和持久型。
1.非持久型,也叫反射型XSS。經過GET和POST方法,向服務器端輸入數據。用戶輸入的數據一般被放置在URL的query string中,或者是form 數據中。若是服務器端對輸入的數據不進行過濾,驗證或編碼,就直接將用戶輸入的信息直接呈現給客戶,則可能會形成反射型XSS。反射型XSS是比較廣泛的XSS,其危害程度一般被認爲較小。可是某些反射型XSS形成的後果會很嚴重,如在輸入框的name中輸入<meta http-equiv="refresh" content="5" />,服務器不加處理,將name的值直接送到瀏覽器,則瀏覽器會每5秒自動刷新一次。嚴重者會致使服務器崩潰。
2.持久型,也叫存儲型XSS。一般是由於服務器端將用戶輸入的惡意腳本沒有經過驗證就直接存儲在數據庫,而且每次經過調用數據庫的方式,將數據呈如今瀏覽器上。則該XSS跨站腳本攻擊將一直存在。若其餘用戶訪問該頁面,則惡意腳本就會被觸發,用於盜取其餘用戶的私人信息。
經常使用XSS方式分爲如下幾種:
1. 輸入框中直接輸入惡意腳本,如:
><script>alert(document.cookie)</script>
2. 輸入框中輸入html標籤,在標籤中嵌入惡意腳本,如src,href,css style等。
<IMG SRC="javascript:alert('XSS');">;
<BODY BACKGROUND="javascript:alert('XSS')">
<STYLE>li {list-style-image: url("javascript:alert('XSS')");}</STYLE><UL><LI>XSS</br>
3.將惡意腳本注入在event事件中,如onClick,onBlur,onMouseOver等事件。
<a onmouseover="alert(document.cookie)">xxs link</a>
4. 在remote style sheet,javascript中,如
<LINK REL="stylesheet" HREF="javascript:alert('XSS');">
<SCRIPT/SRC="http://ha.ckers.org/xss.js"></SCRIPT>
5. META 標籤,如
<meta http-equiv="refresh" content="5" />
<META HTTP-EQUIV="Set-Cookie" Content="USERID=<SCRIPT>alert('XSS')</SCRIPT>">
如何預防以上兩種XSS攻擊?
1. 在輸入流中截住form data中的惡意腳本
研究兩種XSS攻擊,如反射型和存儲型XSS攻擊,其惡意腳本都是來自用戶的輸入。所以,可使用過濾用戶輸入的方法對惡意腳本進行過濾。對簡單的HTTP請求,通常使用GET和POST方法。當使用GET時,用戶輸入的數據將被放入地址欄的URL中,如:http://xxxx?name1=value1&name2=value2…..。其中,URL以後會放入鍵值對,對應name1的值爲value1,name2的值爲value2,等等。而對於POST方法,則用戶輸入數據仍然以name1=value1&name2=value2.。。。,可是數據鍵值對不會放進URL以後,而是放進了request的body中。所以,咱們獲得一個結論,全部的數據都存儲在request中,咱們能夠截下進入server的每個request,對用戶的輸入數據進行惡意腳本清理。其中有效的一個方法就是使用spring的filter。代碼示例以下,在web.xml中加入如下代碼段:
<filter>
<filter-name>XSS</filter-name>
<filter-class>com.springapp.domain.XssFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>XSS</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
其中XssFilter爲自定義的class,該類必須實現Filter類,在XssFilter類中實現doFilter函數。
public class XssFilter implements Filter {
private FilterConfig filterConfig;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(new RequestWrapper((HttpServletRequest) request), new ResponseWrapper((HttpServletResponse) response));
}
@Override
public void destroy() {
this.filterConfig = null;
}
}
那麼咱們怎樣對每一個request都進行過濾操做呢?怎麼樣對用戶輸入的數據進行操做呢?form數據都存儲在什麼地方傳給servlet的呢?
一般狀況下,能夠經過調用request.getParameter來得到單個對應name對應的value。若form的傳入參數中,一個name值對應多個value,則可使用request.getParameterValues來得到name值的多個對應值。少數狀況下,當你須要raw request的適合,可使用getReader和getInputStream。
可是咱們能夠發現,直接對httpServletRequest的parameter進行set操做會報錯,所以須要使用HttpServletRequestWrapper。HttpServletRequestWrapper容許咱們重寫servletRequest的各類方法,以便對request進行直接操做。
所以,咱們能夠在自定義的RequestWrapper中,對getParameter和getParameterValues進行重寫,從而達到對各個用戶輸入的form參數的值進行過濾,濾掉form data中的惡意腳本。如下爲示例代碼:
public String[] getParameterValues(String parameter) {
String[] values = super.getParameterValues(parameter);
if (values==null) {
return null;
}
int count = values.length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = xssClean(values[i]);
}
return encodedValues;
}
public String getParameter(String parameter) {
String value = super.getParameter(parameter);
if (value == null) {
return null;
}
return xssClean(value);
}
2. 在輸入流中檢測濾掉來自其餘網站的URL中的惡意腳本
當用戶不當心點擊了被其餘黑客提供的假冒URL,則可能在該URL中注入惡意腳本。所以,也須要對這種狀況進行處理。所以爲確保其餘在header中的惡意腳本,須要對request.getHeader進行重寫。如下爲例子:
public String getHeader(String name) {
String value = super.getHeader(name);
if (value == null)
return null;
return xssClean(value);
}
3. xssClean函數怎樣實現才能夠過濾掉惡意腳本呢?
若是是java語言,推薦使用antisamy。使用antisamy進行XSS清理很是簡單,只須要簡單的幾個步驟便可達到目的。
1‘. 在pom.xml文件中加入antisamy的dependency,
<dependency>
<groupId>org.owasp.antisamy</groupId>
<artifactId>antisamy</artifactId>
<version>1.5.3</version>
</dependency>
2’. 加入了dependency以後,就能夠在xssClean中加入antisamy對惡意腳本進行清理。其中policy.xml是白名單,policy.xml中規定了各個html元素所必須知足的條件。antisamy的精髓之處在於,使用policy文件來規定你的過濾條件,若輸入字符串不知足policy文件中的條件,則會過濾掉字符中的惡意腳本,返回過濾後的結果。具體代碼以下:
private String xssClean(String value) {
AntiSamy antiSamy = new AntiSamy();
try {
final CleanResults cr = antiSamy.scan(value, Policy.getInstance("policy.xml"), AntiSamy.SAX);
return cr.getCleanHTML();
} catch (ScanException e) {
e.printStackTrace();
} catch (PolicyException e) {
e.printStackTrace();
}
return value;
}
這樣,咱們就將client端用戶輸入的request,在server端進行了攔截,而且進行了過濾。對於輸出端,XSS的防護將在下一篇文章中進行詳細介紹。
轉載請註明出處,謝謝。javascript