日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
前端安全保障之如何防止XSS攻擊?

 前端安全

隨著互聯(lián)網(wǎng)的高速發(fā)展,信息安全問題已經(jīng)成為企業(yè)最為關(guān)注的焦點之一,而前端又是引發(fā)企業(yè)安全問題的高危據(jù)點。在移動互聯(lián)網(wǎng)時代,前端人員除了傳統(tǒng)的 XSS、CSRF 等安全問題之外,又時常遭遇網(wǎng)絡(luò)劫持、非法調(diào)用 Hybrid API 等新型安全問題。當(dāng)然,瀏覽器自身也在不斷在進化和發(fā)展,不斷引入 CSP、Same-Site Cookies 等新技術(shù)來增強安全性,但是仍存在很多潛在的威脅,這需要前端技術(shù)人員不斷進行“查漏補缺”。

近幾年,美團業(yè)務(wù)高速發(fā)展,前端隨之面臨很多安全挑戰(zhàn),因此積累了大量的實踐經(jīng)驗。我們梳理了常見的前端安全問題以及對應(yīng)的解決方案,將會做成一個系列,希望可以幫助前端人員在日常開發(fā)中不斷預(yù)防和修復(fù)安全漏洞。本文是該系列的第一篇。

本文我們會講解 XSS ,主要包括:

  1.  XSS 攻擊的介紹
  2.  XSS 攻擊的分類
  3.  XSS 攻擊的預(yù)防和檢測
  4.  XSS 攻擊的總結(jié)
  5.  XSS 攻擊案例

XSS 攻擊的介紹

在開始本文之前,我們先提出一個問題,請判斷以下兩個說法是否正確:

  1.  XSS 防范是后端 RD(研發(fā)人員)的責(zé)任,后端 RD 應(yīng)該在所有用戶提交數(shù)據(jù)的接口,對敏感字符進行轉(zhuǎn)義,才能進行下一步操作。
  2.  所有要插入到頁面上的數(shù)據(jù),都要通過一個敏感字符過濾函數(shù)的轉(zhuǎn)義,過濾掉通用的敏感字符后,就可以插入到頁面中。

如果你還不能確定答案,那么可以帶著這些問題向下看,我們將逐步拆解問題。

XSS 漏洞的發(fā)生和修復(fù)

XSS 攻擊是頁面被注入了惡意的代碼,為了更形象的介紹,我們用發(fā)生在小明同學(xué)身邊的事例來進行說明。

一個案例

某天,公司需要一個搜索頁面,根據(jù) URL 參數(shù)決定關(guān)鍵詞的內(nèi)容。小明很快把頁面寫好并且上線。代碼如下:

 
 
 
  1. ">  
  2.   
  3.   
  4.   您搜索的關(guān)鍵詞是:<%= getParameter("keyword") %>  
 

然而,在上線后不久,小明就接到了安全組發(fā)來的一個神秘鏈接:

http://xxx/search?keyword=">

小明帶著一種不祥的預(yù)感點開了這個鏈接[請勿模仿,確認安全的鏈接才能點開]。果然,頁面中彈出了寫著"XSS"的對話框。

可惡,中招了!小明眉頭一皺,發(fā)現(xiàn)了其中的奧秘:

當(dāng)瀏覽器請求 http://xxx/search?keyword="> 時,服務(wù)端會解析出請求參數(shù) keyword,得到 ">,拼接到 HTML 中返回給瀏覽器。形成了如下的 HTML:

 
 
 
  1. ">  
  2.   
  3.   
  4.   您搜索的關(guān)鍵詞是:">  
 

瀏覽器無法分辨出 是惡意代碼,因而將其執(zhí)行。

這里不僅僅 div 的內(nèi)容被注入了,而且 input 的 value 屬性也被注入, alert 會彈出兩次。

面對這種情況,我們應(yīng)該如何進行防范呢?

其實,這只是瀏覽器把用戶的輸入當(dāng)成了腳本進行了執(zhí)行。那么只要告訴瀏覽器這段內(nèi)容是文本就可以了。

聰明的小明很快找到解決方法,把這個漏洞修復(fù):

 
 
 
  1. ">  
  2.   
  3.   
  4.   您搜索的關(guān)鍵詞是:<%= escapeHTML(getParameter("keyword")) %>  
 

escapeHTML() 按照如下規(guī)則進行轉(zhuǎn)義:

字符轉(zhuǎn)義后的字符
&&
<<
>>
""
''
//

經(jīng)過了轉(zhuǎn)義函數(shù)的處理后,最終瀏覽器接收到的響應(yīng)為:

 
 
 
  1.   
  2.   
  3.   
  4.   您搜索的關(guān)鍵詞是:"><script>alert('XSS');</script>  
 

惡意代碼都被轉(zhuǎn)義,不再被瀏覽器執(zhí)行,而且搜索詞能夠完美的在頁面顯示出來。

通過這個事件,小明學(xué)習(xí)到了如下知識:

  •  通常頁面中包含的用戶輸入內(nèi)容都在固定的容器或者屬性內(nèi),以文本的形式展示。
  •  攻擊者利用這些頁面的用戶輸入片段,拼接特殊格式的字符串,突破原有位置的限制,形成了代碼片段。
  •  攻擊者通過在目標(biāo)網(wǎng)站上注入腳本,使之在用戶的瀏覽器上運行,從而引發(fā)潛在風(fēng)險。
  •  通過 HTML 轉(zhuǎn)義,可以防止 XSS 攻擊。[事情當(dāng)然沒有這么簡單啦!請繼續(xù)往下看]。

注意特殊的 HTML 屬性、JavaScript API

自從上次事件之后,小明會小心的把插入到頁面中的數(shù)據(jù)進行轉(zhuǎn)義。而且他還發(fā)現(xiàn)了大部分模板都帶有的轉(zhuǎn)義配置,讓所有插入到頁面中的數(shù)據(jù)都默認進行轉(zhuǎn)義。這樣就不怕不小心漏掉未轉(zhuǎn)義的變量啦,于是小明的工作又漸漸變得輕松起來。

但是,作為導(dǎo)演的我,不可能讓小明這么簡單、開心地改 Bug 。

不久,小明又收到安全組的神秘鏈接:http://xxx/?redirect_to=javascript:alert('XSS')。小明不敢大意,趕忙點開頁面。然而,頁面并沒有自動彈出萬惡的“XSS”。

小明打開對應(yīng)頁面的源碼,發(fā)現(xiàn)有以下內(nèi)容:

 
 
 
  1. ">跳轉(zhuǎn)... 

這段代碼,當(dāng)攻擊 URL 為 http://xxx/?redirect_to=javascript:alert('XSS'),服務(wù)端響應(yīng)就成了:

 
 
 
  1. 跳轉(zhuǎn)... 

雖然代碼不會立即執(zhí)行,但一旦用戶點擊 a 標(biāo)簽時,瀏覽器會就會彈出“XSS”。

可惡,又失策了...

在這里,用戶的數(shù)據(jù)并沒有在位置上突破我們的限制,仍然是正確的 href 屬性。但其內(nèi)容并不是我們所預(yù)期的類型。

原來不僅僅是特殊字符,連 javascript: 這樣的字符串如果出現(xiàn)在特定的位置也會引發(fā) XSS 攻擊。

小明眉頭一皺,想到了解決辦法:

 
 
 
  1. // 禁止 URL 以 "javascript:" 開頭  
  2. xss = getParameter("redirect_to").startsWith('javascript:');  
  3. if (!xss) {  
  4.   ">  
  5.     跳轉(zhuǎn)...  
  6.     
  7. } else {  
  8.     
  9.     跳轉(zhuǎn)...  
  10.     

只要 URL 的開頭不是 javascript:,就安全了吧?

安全組隨手又扔了一個連接:http://xxx/?redirect_to=jAvascRipt:alert('XSS')

這也能執(zhí)行?.....好吧,瀏覽器就是這么強大。

小明欲哭無淚,在判斷 URL 開頭是否為 javascript: 時,先把用戶輸入轉(zhuǎn)成了小寫,然后再進行比對。

不過,所謂“道高一尺,魔高一丈”。面對小明的防護策略,安全組就構(gòu)造了這樣一個連接:

http://xxx/?redirect_to=%20javascript:alert('XSS')

%20javascript:alert('XSS') 經(jīng)過 URL 解析后變成 javascript:alert('XSS'),這個字符串以空格開頭。這樣攻擊者可以繞過后端的關(guān)鍵詞規(guī)則,又成功的完成了注入。

最終,小明選擇了白名單的方法,徹底解決了這個漏洞:

 
 
 
  1. // 根據(jù)項目情況進行過濾,禁止掉 "javascript:" 鏈接、非法 scheme 等  
  2. allowSchemes = ["http", "https"];  
  3. valid = isValid(getParameter("redirect_to"), allowSchemes);  
  4. if (valid) {  
  5.   ">  
  6.     跳轉(zhuǎn)...  
  7.     
  8. } else {  
  9.     
  10.     跳轉(zhuǎn)...  
  11.     

通過這個事件,小明學(xué)習(xí)到了如下知識:

  •  做了 HTML 轉(zhuǎn)義,并不等于高枕無憂。
  •  對于鏈接跳轉(zhuǎn),如

根據(jù)上下文采用不同的轉(zhuǎn)義規(guī)則

某天,小明為了加快網(wǎng)頁的加載速度,把一個數(shù)據(jù)通過 JSON 的方式內(nèi)聯(lián)到 HTML 中:

 
 
 
  1.  

插入 JSON 的地方不能使用 escapeHTML(),因為轉(zhuǎn)義 " 后,JSON 格式會被破壞。

但安全組又發(fā)現(xiàn)有漏洞,原來這樣內(nèi)聯(lián) JSON 也是不安全的:

  •  當(dāng) JSON 中包含 U+2028 或 U+2029 這兩個字符時,不能作為 JavaScript 的字面量使用,否則會拋出語法錯誤。
  •  當(dāng) JSON 中包含字符串 時,當(dāng)前的 script 標(biāo)簽將會被閉合,后面的字符串內(nèi)容瀏覽器會按照 HTML 進行解析;通過增加下一個   
  •   
  •   
  •   
  •   onclick="alert('<%= Encode.forJavaScript(UNTRUSTED) %>');">  
  •   click me  
  •   
  •   
  • &order=1#top">  
  •   
  • ">  
  •   
  •   urlValidator.isValid(UNTRUSTED) ?  
  •     Encode.forHtml(UNTRUSTED) :  
  •     "/404"  
  • %>'>  
  •   link  
  •  
  • 可見,HTML 的編碼是十分復(fù)雜的,在不同的上下文里要使用相應(yīng)的轉(zhuǎn)義規(guī)則。

    預(yù)防 DOM 型 XSS 攻擊

    DOM 型 XSS 攻擊,實際上就是網(wǎng)站前端 JavaScript 代碼本身不夠嚴謹,把不可信的數(shù)據(jù)當(dāng)作代碼執(zhí)行了。

    在使用 .innerHTML、.outerHTML、document.write() 時要特別小心,不要把不可信的數(shù)據(jù)作為 HTML 插到頁面上,而應(yīng)盡量使用 .textContent、.setAttribute() 等。

    如果用 Vue/React 技術(shù)棧,并且不使用 v-html/dangerouslySetInnerHTML 功能,就在前端 render 階段避免 innerHTML、outerHTML 的 XSS 隱患。

    DOM 中的內(nèi)聯(lián)事件監(jiān)聽器,如 location、onclick、onerror、onload、onmouseover 等, 標(biāo)簽的 href 屬性,JavaScript 的 eval()、setTimeout()、setInterval() 等,都能把字符串作為代碼運行。如果不可信的數(shù)據(jù)拼接到字符串中傳遞給這些 API,很容易產(chǎn)生安全隱患,請務(wù)必避免。

     
     
     
    1.   
    2.   
    3.   
    4. 1  
    5.  

    如果項目中有用到這些的話,一定要避免在字符串中拼接不可信數(shù)據(jù)。

    其他 XSS 防范措施

    雖然在渲染頁面和執(zhí)行 JavaScript 時,通過謹慎的轉(zhuǎn)義可以防止 XSS 的發(fā)生,但完全依靠開發(fā)的謹慎仍然是不夠的。以下介紹一些通用的方案,可以降低 XSS 帶來的風(fēng)險和后果。

    Content Security Policy

    嚴格的 CSP 在 XSS 的防范中可以起到以下的作用:

    •  禁止加載外域代碼,防止復(fù)雜的攻擊邏輯。
    •  禁止外域提交,網(wǎng)站被攻擊后,用戶的數(shù)據(jù)不會泄露到外域。
    •  禁止內(nèi)聯(lián)腳本執(zhí)行(規(guī)則較嚴格,目前發(fā)現(xiàn) GitHub 使用)。
    •  禁止未授權(quán)的腳本執(zhí)行(新特性,Google Map 移動版在使用)。
    •  合理使用上報可以及時發(fā)現(xiàn) XSS,利于盡快修復(fù)問題。

    關(guān)于 CSP 的詳情,請關(guān)注前端安全系列后續(xù)的文章。

    輸入內(nèi)容長度控制

    對于不受信任的輸入,都應(yīng)該限定一個合理的長度。雖然無法完全防止 XSS 發(fā)生,但可以增加 XSS 攻擊的難度。

    其他安全措施

    •  HTTP-only Cookie: 禁止 JavaScript 讀取某些敏感 Cookie,攻擊者完成 XSS 注入后也無法竊取此 Cookie。
    •  驗證碼:防止腳本冒充用戶提交危險操作。

    XSS 的檢測

    上述經(jīng)歷讓小明收獲頗豐,他也學(xué)會了如何去預(yù)防和修復(fù) XSS 漏洞,在日常開發(fā)中也具備了相關(guān)的安全意識。但對于已經(jīng)上線的代碼,如何去檢測其中有沒有 XSS 漏洞呢?

    經(jīng)過一番搜索,小明找到了兩個方法:

    1.  使用通用 XSS 攻擊字符串手動檢測 XSS 漏洞。
    2.  使用掃描工具自動檢測 XSS 漏洞。

    在Unleashing an Ultimate XSS Polyglot一文中,小明發(fā)現(xiàn)了這么一個字符串:

     
     
     
    1. jaVasCript:/*-/*`/*\`/*'/*"/**/(/* */oNcliCk=alert() )//%0D%0A%0d%0a//\x3csVg/\x3e 

    它能夠檢測到存在于 HTML 屬性、HTML 文字內(nèi)容、HTML 注釋、跳轉(zhuǎn)鏈接、內(nèi)聯(lián) JavaScript 字符串、內(nèi)聯(lián) CSS 樣式表等多種上下文中的 XSS 漏洞,也能檢測 eval()、setTimeout()、setInterval()、Function()、innerHTML、document.write() 等 DOM 型 XSS 漏洞,并且能繞過一些 XSS 過濾器。

    小明只要在網(wǎng)站的各輸入框中提交這個字符串,或者把它拼接到 URL 參數(shù)上,就可以進行檢測了。

     
     
     
    1. http://xxx/search?keyword=jaVasCript%3A%2F*-%2F*%60%2F*%60%2F*%27%2F*%22%2F**%2F(%2F*%20*%2FoNcliCk%3Dalert()%20)%2F%2F%250D%250A%250d%250a%2F%2F%3C%2FstYle%2F%3C%2FtitLe%2F%3C%2FteXtarEa%2F%3C%2FscRipt%2F--!%3E%3CsVg%2F%3CsVg%2FoNloAd%3Dalert()%2F%2F%3E%3E 

     除了手動檢測之外,還可以使用自動掃描工具尋找 XSS 漏洞,例如 Arachni、Mozilla HTTP Observatory、w3af 等。

    XSS 攻擊的總結(jié)

    我們回到最開始提出的問題,相信同學(xué)們已經(jīng)有了答案:

    1.XSS 防范是后端 RD 的責(zé)任,后端 RD 應(yīng)該在所有用戶提交數(shù)據(jù)的接口,對敏感字符進行轉(zhuǎn)義,才能進行下一步操作。

    不正確。因為:

    • 防范存儲型和反射型 XSS 是后端 RD 的責(zé)任。而 DOM 型 XSS 攻擊不發(fā)生在后端,是前端 RD 的責(zé)任。防范 XSS 是需要后端 RD 和前端 RD 共同參與的系統(tǒng)工程。

    • 轉(zhuǎn)義應(yīng)該在輸出 HTML 時進行,而不是在提交用戶輸入時。

    2. 所有要插入到頁面上的數(shù)據(jù),都要通過一個敏感字符過濾函數(shù)的轉(zhuǎn)義,過濾掉通用的敏感字符后,就可以插入到頁面中。

    不正確。

    不同的上下文,如 HTML 屬性、HTML 文字內(nèi)容、HTML 注釋、跳轉(zhuǎn)鏈接、內(nèi)聯(lián) JavaScript 字符串、內(nèi)聯(lián) CSS 樣式表等,所需要的轉(zhuǎn)義規(guī)則不一致。

    業(yè)務(wù) RD 需要選取合適的轉(zhuǎn)義庫,并針對不同的上下文調(diào)用不同的轉(zhuǎn)義規(guī)則。

    整體的 XSS 防范是非常復(fù)雜和繁瑣的,我們不僅需要在全部需要轉(zhuǎn)義的位置,對數(shù)據(jù)進行對應(yīng)的轉(zhuǎn)義。而且要防止多余和錯誤的轉(zhuǎn)義,避免正常的用戶輸入出現(xiàn)亂碼。

    雖然很難通過技術(shù)手段完全避免 XSS,但我們可以總結(jié)以下原則減少漏洞的產(chǎn)生:

    •  利用模板引擎

        開啟模板引擎自帶的 HTML 轉(zhuǎn)義功能。例如:

        在 ejs 中,盡量使用 <%= data %> 而不是 <%- data %>;

        在 doT.js 中,盡量使用 {{! data } 而不是 {{= data };

        在 FreeMarker 中,確保引擎版本高于 2.3.24,并且選擇正確的 freemarker.core.OutputFormat。

    •  避免內(nèi)聯(lián)事件

        盡量不要使用 onLoad="onload('{{data}}')"、onClick="go('{{action}}')" 這種拼接內(nèi)聯(lián)事件的寫法。在 JavaScript 中通過 .addEventlistener() 事件綁定會更安全。

    •  避免拼接 HTML

        前端采用拼接 HTML 的方法比較危險,如果框架允許,使用 createElement、setAttribute 之類的方法實現(xiàn)?;蛘卟捎帽容^成熟的渲染框架,如 Vue/React 等。

    •  時刻保持警惕

        在插入位置為 DOM 屬性、鏈接等位置時,要打起精神,嚴加防范。

    •  增加攻擊難度,降低攻擊后果

        通過 CSP、輸入長度配置、接口安全措施等方法,增加攻擊的難度,降低攻擊的后果。

    •  主動檢測和發(fā)現(xiàn)

        可使用 XSS 攻擊字符串和自動掃描工具尋找潛在的 XSS 漏洞。

    XSS 攻擊案例

    QQ 郵箱 m.exmail.qq.com 域名反射型 XSS 漏洞

    攻擊者發(fā)現(xiàn) http://m.exmail.qq.com/cgi-bin/login?uin=aaaa&domain=bbbb 這個 URL 的參數(shù) uin、domain 未經(jīng)轉(zhuǎn)義直接輸出到 HTML 中。

    于是攻擊者構(gòu)建出一個 URL,并引導(dǎo)用戶去點擊:

    http://m.exmail.qq.com/cgi-bin/login?uin=aaaa&domain=bbbb%26quot%3B%3Breturn+false%3B%26quot%3B%26lt%3B%2Fscript%26gt%3B%26lt%3Bscript%26gt%3Balert(document.cookie)%26lt%3B%2Fscript%26gt%3B

    用戶點擊這個 URL 時,服務(wù)端取出 URL 參數(shù),拼接到 HTML 響應(yīng)中:

     
     
     
    1. "+"...  

    瀏覽器接收到響應(yīng)后就會執(zhí)行 alert(document.cookie),攻擊者通過 JavaScript 即可竊取當(dāng)前用戶在 QQ 郵箱域名下的 Cookie ,進而危害數(shù)據(jù)安全。

    新浪微博名人堂反射型 XSS 漏洞

    攻擊者發(fā)現(xiàn) http://weibo.com/pub/star/g/xyyyd 這個 URL 的內(nèi)容未經(jīng)過濾直接輸出到 HTML 中。

    于是攻擊者構(gòu)建出一個 URL,然后誘導(dǎo)用戶去點擊:

    http://weibo.com/pub/star/g/xyyyd">

    用戶點擊這個 URL 時,服務(wù)端取出請求 URL,拼接到 HTML 響應(yīng)中:

     
     
     
    1. ">按分類檢索
    2.  

    瀏覽器接收到響應(yīng)后就會加載執(zhí)行惡意腳本 //xxxx.cn/image/t.js,在惡意腳本中利用用戶的登錄狀態(tài)進行關(guān)注、發(fā)微博、發(fā)私信等操作,發(fā)出的微博和私信可再帶上攻擊 URL,誘導(dǎo)更多人點擊,不斷放大攻擊范圍。這種竊用受害者身份發(fā)布惡意內(nèi)容,層層放大攻擊范圍的方式,被稱為“XSS 蠕蟲”。

    擴展閱讀:Automatic Context-Aware Escaping

    上文我們說到:

    1.  合適的 HTML 轉(zhuǎn)義可以有效避免 XSS 漏洞。
    2.  完善的轉(zhuǎn)義庫需要針對上下文制定多種規(guī)則,例如 HTML 屬性、HTML 文字內(nèi)容、HTML 注釋、跳轉(zhuǎn)鏈接、內(nèi)聯(lián) JavaScript 字符串、內(nèi)聯(lián) CSS 樣式表等等。
    3.  業(yè)務(wù) RD 需要根據(jù)每個插入點所處的上下文,選取不同的轉(zhuǎn)義規(guī)則。

    通常,轉(zhuǎn)義庫是不能判斷插入點上下文的(Not Context-Aware),實施轉(zhuǎn)義規(guī)則的責(zé)任就落到了業(yè)務(wù) RD 身上,需要每個業(yè)務(wù) RD 都充分理解 XSS 的各種情況,并且需要保證每一個插入點使用了正確的轉(zhuǎn)義規(guī)則。

    這種機制工作量大,全靠人工保證,很容易造成 XSS 漏洞,安全人員也很難發(fā)現(xiàn)隱患。

    2009年,Google 提出了一個概念叫做:Automatic Context-Aware Escaping。

    所謂 Context-Aware,就是說模板引擎在解析模板字符串的時候,就解析模板語法,分析出每個插入點所處的上下文,據(jù)此自動選用不同的轉(zhuǎn)義規(guī)則。這樣就減輕了業(yè)務(wù) RD 的工作負擔(dān),也減少了人為帶來的疏漏。

    在一個支持 Automatic Context-Aware Escaping 的模板引擎里,業(yè)務(wù) RD 可以這樣定義模板,而無需手動實施轉(zhuǎn)義規(guī)則:

     
     
     
    1.   
    2.     
    3.       
    4.     {{.title}}  
    5.     
    6.     
    7.     {{.content}}  
    8.     
    9.  

    模板引擎經(jīng)過解析后,得知三個插入點所處的上下文,自動選用相應(yīng)的轉(zhuǎn)義規(guī)則:

     
     
     
    1.   
    2.     
    3.       
    4.     {{.title | htmlescaper}}  
    5.     
    6.     
    7.     {{.content | htmlescaper}}  
    8.     
    9.  

    目前已經(jīng)支持 Automatic Context-Aware Escaping 的模板引擎有:

    •  go html/template
    •  Google Closure Templates 

    文章標(biāo)題:前端安全保障之如何防止XSS攻擊?
    地址分享:http://www.dlmjj.cn/article/cceoghh.html