跨站腳本(XSS)

1.1 XSS定義

XSS,即爲(Cross Site Scripting),中文名爲跨站腳本,是發生在目標用戶的瀏覽器層面上的,當渲染DOM樹的過程發生了不在預期內執行的JS代碼時,就發生了XSS攻擊。javascript

跨站腳本的重點不在「跨站」上,而在於「腳本」上。大多數XSS攻擊的主要方式就是嵌入一段遠程或者第三方域上的JS代碼。其實是在目標網站的做用域下執行了這段JS代碼。css

1.2 XSS攻擊方式

1.2.1 反射型 XSS

反射型XSS,也叫非持久型XSS,是指發生請求時,XSS代碼出如今請求URL中,做爲參數提交到服務器,服務器解析並響應。響應結果中包含XSS代碼,最後瀏覽器解析並執行。html

從概念上能夠看出,反射型XSS代碼是首先出如今URL中的,而後須要服務端解析,最後須要瀏覽器解析以後XSS代碼纔可以攻擊。前端

 

舉一個小例子java

使用express起一個web服務器,而後設置一下請求接口。經過ajax的GET請求將參數發往服務器,服務器解析成json後響應。將返回的數據解析後顯示到頁面上。(沒有對返回的數據進行解碼和過濾等操做。)node

 1 html
 2 <textarea name="txt" id="txt" cols="80" rows="10">
 3 <button type="button" id="test">測試</button>
 4 
 5 js
 6 var test = document.querySelector('#test')
 7 test.addEventListener('click', function () {
 8   var url = `/test?test=${txt.value}`   // 1. 發送一個GET請求
 9   var xhr = new XMLHttpRequest()
10   xhr.onreadystatechange = function () {
11     if (xhr.readyState === 4) {
12       if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
13         // 3. 客戶端解析JSON,並執行
14         var str = JSON.parse(xhr.responseText).test
15         var node = `${str}`
16         document.body.insertAdjacentHTML('beforeend', node)
17       } else {
18         console.log('error', xhr.responseText)
19       }
20     }
21   }
22   xhr.open('GET', url, true)
23   xhr.send(null)
24 }, false)
25 
26 express
27 var express = require('express');
28 var router = express.Router();
29 
30 router.get('/test', function (req, res, next) {
31  // 2. 服務端解析成JSON後響應
32   res.json({
33     test: req.query.test
34   })
35 })
View Code

如今咱們經過給textarea添加一段有攻擊目的的img標籤,git

<img src="null" onerror='alert(document.cookie)' />

實際的頁面時這樣的。github

ok如今,咱們點擊<測試>按鈕,一個XSS攻擊就發生了。下面圖片中是獲取了本地的部分cookie信息web

實際上,咱們只是模擬攻擊,經過alert獲取到了我的的cookie信息。可是若是是黑客的話,他們會注入一段第三方的js代碼,而後將獲取到的cookie信息存到他們的服務器上。這樣的話黑客們就有機會拿到咱們的身份認證作一些違法的事情了。ajax

以上,存在的一些問題,主要在於沒有對用戶輸入的信息進行過濾,同時沒有剔除掉DOM節點中存在的一些有危害的事件和一些有危害的DOM節點。

1.2.3 存儲型 XSS

存儲型XSS,也叫持久型XSS,主要是將XSS代碼發送到服務器(不論是數據庫、內存仍是文件系統等。),而後在下次請求頁面的時候就不用帶上XSS代碼了。

最典型的就是留言板XSS。用戶提交了一條包含XSS代碼的留言到數據庫。當目標用戶查詢留言時,那些留言的內容會從服務器解析以後加載出來。瀏覽器發現有XSS代碼,就當作正常的HTML和JS解析執行。XSS攻擊就發生了。

1.2.4 DOM XSS

DOM XSS攻擊不一樣於反射型XSS和存儲型XSS,DOM XSS代碼不須要服務器端的解析響應的直接參與,而是經過瀏覽器端的DOM解析。這徹底是客戶端的事情。

DOM XSS代碼的攻擊發生的可能在於咱們編寫JS代碼形成的。咱們知道eval語句有一個做用是將一段字符串轉換爲真正的JS語句,所以在JS中使用eval是很危險的事情,容易形成XSS攻擊。避免使用eval語句。

如如下代碼:

1 test.addEventListener('click', function () {
2   var node = window.eval(txt.value)
3   window.alert(node)
4 }, false)
5 
6 txt中的代碼以下
7 <img src='null' onerror='alert(123)' />
View Code

以上經過eval語句就形成了XSS攻擊。

1.2.5 XSS危害

  • 經過document.cookie盜取cookie

  • 使用js或css破環頁面正常的結構與樣式

  • 流量劫持(經過訪問某段具備window.location.href定位到其餘頁面)

  • Dos攻擊:利用合理的客戶端請求來佔用過多的服務器資源,從而使合法的用戶沒法獲得服務器響應

  • 利用iframe、frame、XMLHttpRequest或上述Flash等方式,以(被攻擊)用戶的身份執行一些管理動做,或執行一些通常的如發微博、加好友、發私信等操做。

  • 利用可被攻擊的域受到其餘域信任的特色,以受信任來源的身份請求一些平時不容許的操做,如進行不當的投票活動。

1.3 XSS防護

從以上的反射型DOM XSS能夠看出,咱們不能原樣的將用戶輸入的數據直接存在服務器,須要對數據進行一些處理,以上代碼的一些問題以下:

  • 沒有過濾危險的DOM節點。若是具備執行腳本能力的script,具備顯示廣告和色情圖片的img,具備改變樣式的link,style,具備內嵌頁面的iframe,frame等元素節點。

  • 沒有過濾危險的屬性節點。如事件,style,src,href等

  • 沒有對cookie設置httpOnly

  • 若是將以上三點都在渲染過程當中過濾,那麼出現的XSS攻擊的改了也就小不少。

解決方法以下

1.3.1 對cookie的保護

1.對重要的cookie設置httpOnly,防止客戶端經過document.cookie讀取cookie。服務端能夠設置此字段。

 

1.3.2 對用戶輸入數據的處理

1.編碼:不能對用戶輸入的內容都保持原樣,對用書輸入的數據進行字符實體編碼。對於字符實體

2.解碼:原樣顯示內容的時候必須解碼,否則顯示不到內容了。

3.過濾:把輸入的一些不合法的東西都過濾掉,從而保證安全性。如移除用戶上傳的DOM屬性,如onerror,移除用戶上傳的Style節點,iframe, script節點等。

經過一個例子講解一下如何處理用戶輸入的數據。

實現原理以下:

  1. 存在一個parse函數,對輸入的數據進行處理,返回處理以後的數據

  2. 對輸入的數據(如DOM節點)進行解碼(使用第三方庫 he.js)

  3. 過濾掉一些元素有危害的元素節點與屬性節點。如script標籤,onerror事件等。(使用第三方庫HTMLParser.js)

 1 <script src='/javascripts/htmlparse.js'></script>
 2 <script src='/javascripts/he.js'></script>
 3 // 第三方庫資源在文章底部給出
 4 
 5 // parse函數實現以下
 6 
 7 function parse (str) {
 8       // str假如爲某個DOM字符串
 9       // 1. result爲處理以後的DOM節點
10       let result = ''
11       // 2. 解碼
12       let decode = he.unescape(str, {
13           strict: true
14       })
15       HTMLParser(decode, {
16           start (tag, attrs, unary) {
17               // 3. 過濾常見危險的標籤
18               if (tag === 'script' || tag === 'img' || tag === 'link' || tag === 'style' || tag === 'iframe' || tag === 'frame') return
19               result += `<${tag}`
20               for (let i = 0; i < attrs.length; i++) {
21                   let name = (attrs[i].name).toLowerCase()
22                   let value = attrs[i].escaped
23                   // 3. 過濾掉危險的style屬性和js事件
24                   if (name === 'style' || name === 'href' || name === 'src' || ~name.indexOf('on')) continue
25                   result += ` ${name}=${value}`
26               }
27               result += `${unary ? ' /' : ''} >`
28           },
29           chars (text) {
30               result += text
31           },
32           comment (text) {
33               result += `<!-- ${text} -->`
34           },
35           end (tag) {
36               result += `</${tag}>`
37           }
38       })
39       return result
40   }
View Code

所以,有了以上的parse函數以後,就能夠避免大部分的xss攻擊了。

 1 test.addEventListener('click', function () {
 2   // ... 省略部分代碼
 3   xhr.onreadystatechange = function () {
 4     if (xhr.readyState === 4) {
 5       if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
 6         // 3. 客戶端解析JSON,並執行
 7         // test按鈕的點擊事件中惟一的變化就是使用parse對服務端返回的數據進行了解碼和過濾的處理。
 8         var str = parse(JSON.parse(xhr.responseText).test)
 9         // 經過parse解析以後返回的數據就是安全的DOM字符串
10         var node = `${str}`
11         document.body.insertAdjacentHTML('beforeend', node)
12       }
13     }
14   }
15   // ... 省略部分代碼
16 }, false)
View Code

那麼,例子說完了

稍微總結一下

  1. 一旦在DOM解析過程成出現不在預期內的改變(JS代碼執行或樣式大量變化時),就可能發生XSS攻擊

  2. XSS分爲反射型XSS,存儲型XSS和DOM XSS

  3. 反射型XSS是在將XSS代碼放在URL中,將參數提交到服務器。服務器解析後響應,在響應結果中存在XSS代碼,最終經過瀏覽器解析執行。

  4. 存儲型XSS是將XSS代碼存儲到服務端(數據庫、內存、文件系統等),在下次請求同一個頁面時就不須要帶上XSS代碼了,而是從服務器讀取。

  5. DOM XSS的發生主要是在JS中使用eval形成的,因此應當避免使用eval語句。

  6. XSS危害有盜取用戶cookie,經過JS或CSS改變樣式,DDos形成正經常使用戶沒法獲得服務器響應。

  7. XSS代碼的預防主要經過對數據解碼,再過濾掉危險標籤、屬性和事件等。

參考資源

  1. 《WEB前端黑客技術揭祕》

  2. 淺談XSS攻擊的那些事(附經常使用繞過姿式)

  3. XSS實戰:我是如何拿下你的百度帳號

  4. HTMLParser

  5. he

  6. Web安全-XSS

相關文章
相關標籤/搜索