不可忽視的前端安全問題——XSS攻擊

英俊瀟灑你衝哥發表於2019-03-03

XSS是什麼

XSS是跨站指令碼攻擊(Cross-Site Scripting)的簡稱。

XSS是一種注入指令碼式攻擊,攻擊者利用如提交表單、釋出評論等方式將事先準備好的惡意指令碼注入到那些良性可信的網站中,當其他使用者進入該網站後,指令碼就在使用者不知情的情況下偷偷地執行了,這樣的指令碼可能會竊取使用者的資訊、修改頁面內容、或者偽造使用者執行其他操作等等,後果不可估量。

XSS攻擊通常會發生在以下情況下:

  • 向一個web app中輸入含有一些不良程式碼的內容,通常是一段含有http請求的程式碼
  • 這些內容包含在發給其他使用者的動態內容之中,而且這些內容還沒有經過校驗

傳送到Web瀏覽器的惡意內容通常採用JavaScript程式碼片段的形式,但也可能包括HTML,Flash或瀏覽器可能執行的任何其他型別的程式碼。 基於XSS的攻擊方式幾乎是無限的。但是它們通常的方式是:

  • 向攻擊者傳送包括諸如cookie或其他會話資訊的私有資料
  • 攻擊者篡改頁面的內容
  • 在使用者的機器上,以含有漏洞的網站為幌子,執行其他惡意操作

OWASP(Open Web Application Security Project)最新公佈的2017 10項最嚴重的 Web 應用程式安全風險中,XSS榜上有名。

不可忽視的前端安全問題——XSS攻擊

而事實上,XSS在每次的TOP10評比中都會出現……

不可忽視的前端安全問題——XSS攻擊

XSS例項

想知道XSS是如何造成攻擊的?可以看這個下面的文章,它介紹了一個XSS漏洞——XSS跨站指令碼攻擊過程最簡單演示 – CSDN部落格 案例中攻擊者利用XSS可以獲取使用者的隱私資訊。

XSS攻擊的分類

一般會把XSS分為兩類——儲存型XSS(Stored XSS)和反射型XSS(Reflected XSS)

不過還有一種不為人知的型別——DOM-based XSS。


儲存型XSS是指那些將惡意指令碼永久的儲存在目標伺服器上的攻擊方式,如儲存在資料庫、訊息論壇、訪問日誌、評論內容扥等。

反射型XSS是當使用者點選一個惡意連結,或者提交一個表單,或者進入一個惡意網站時,注入指令碼進入被攻擊者的網站。Web伺服器將注入指令碼,比如一個錯誤資訊,搜尋結果等 返回到使用者的瀏覽器上。瀏覽器會執行這段指令碼,因為,它認為這個響應來自可信任的伺服器。一個危險的XSS案例–輕鬆拿到登入使用者的cookie – CSDN部落格,這個例子中,如果有人誘導你點選了上面文章中寫到的連結,那麼你在站酷網站中的隱私資訊就傳送到了其他伺服器中了。

DOM-Based型XSS是指攻擊者利用原生JavaScript程式碼篡改客戶端的DOM結構,導致使用者操作執行了“意外”的動作。

關於DOM-Based型XSS可以看下面的例子

下面是一段網站的程式碼,它提供一個下拉框讓你來選擇語言,而且還根據你URL上的default引數來進行預設語言的推薦。

Select your language:

<select><script>

document.write("<OPTION value=1>"+document.location.href.substring(document.location.href.indexOf("default=")+8)+"</OPTION>");

document.write("<OPTION value=2>English</OPTION>");

</script></select>
…複製程式碼

通常情況下,這個頁面的地址會是下面的樣子:

http://www.some.site/page.html?default=French複製程式碼

而DOM-Based型XSS會利用這個頁面DOM結構的漏洞,向受害者傳送下面的連結

http://www.some.site/page.html?default=<script>alert(document.cookie)</script>複製程式碼

當受害者點開這個連結時,就會將使用者的cookie全部alert出來了。

XSS的防範原則

關於XSS攻擊的防範,我在OWASP上給出防範方法進行了精簡,如果你有興趣的話,可以去看詳細內容

原則0——永遠不要把不受信任的資料插入到原本允許JavaScript可以放置的地方

就像下面的程式碼中所示的那樣:

<script>...永遠不要把不受信任的資料放在這...</script>   直接放在script標籤內
 
 <!--...永遠不要把不受信任的資料放在這...-->             放在HTML註釋內
 
 <div ...永遠不要把不受信任的資料放在這...=test />       做為一個屬性名
 
 <永遠不要把不受信任的資料放在這... href="/test" />   做為一個標籤名
 
 <style>...永遠不要把不受信任的資料放在這...</style>   直接放在style標籤內複製程式碼

原則1——在向元素中插入不受信任的HTML程式碼之前一定要進行轉義

就像下面的程式碼中所示的那樣:

<body>...將不受信任的資料轉義後再放在這...</body>
 
 <div>...將不受信任的資料轉義後再放在這...</div>
 
 any other normal HTML elements複製程式碼

常用的轉義規則如下:

& --> &amp;
 < --> &lt;
 > --> &gt;
 " --> &quot;
 ` --> &#x27; 
 / --> &#x2F;複製程式碼

原則2——在向元素的屬性插入不受信任的HTML程式碼之前一定要進行轉義

看下面的程式碼:

<div attr=...將不受信任的資料轉義後再放在這...>content</div>  
在沒有加引號的屬性值內
 
 <div attr=`...將不受信任的資料轉義後再放在這...`>content</div>
在加了單引號的屬性值內

<div attr="...將不受信任的資料轉義後再放在這...">content</div>
在加了雙引號的屬性值內複製程式碼

原則3——在用不受信任的資料向JavaScript程式碼賦值前,一定要進行轉義

看下面的程式碼:

<script>alert(`...將不受信任的資料轉義後再放在這...`)</script>     
在一個字串之內
 
 <script>x=`...將不受信任的資料轉義後再放在這...`</script> 
在表示式的一側
 
 <div onmouseover="x=`...將不受信任的資料轉義後再放在這...`"</div>  
在事件處理函式內複製程式碼

需要注意的是,有一些JavaScript函式永遠無法安全的使用不受信任的資料作為輸入,比如下面的程式碼:

<script>
 window.setInterval(`即使你做了轉義,但是仍然可能被XSS攻擊`);
 </script>複製程式碼

原則3.1——在HTML的上下文中對JSON值進行轉義,並用JSON.parse()方法來讀取值

一定要確保http response中的頭部資訊的content-type為application/json,而不是text/html,因為那樣的話,很可能會被人利用進行XSS攻擊。

一個壞的案例:

HTTP/1.1 200
   Date: Wed, 06 Feb 2013 10:28:54 GMT
   Server: Microsoft-IIS/7.5....
   Content-Type: text/html; charset=utf-8 <-- bad
   ....
   Content-Length: 373
   Keep-Alive: timeout=5, max=100
   Connection: Keep-Alive
   {"Message":"No HTTP resource was found that matches the request URI `dev.net.ie/api/pay/.html?HouseNumber=9&AddressLine
   =The+Gardens<script>alert(1)</script>&AddressLine2=foxlodge+woods&TownName=Meath`.","MessageDetail":"No type was found
   that matches the controller named `pay`."}   <-- 這裡script標籤有可能會被執行複製程式碼

一個好的案例:

 HTTP/1.1 200
   Date: Wed, 06 Feb 2013 10:28:54 GMT
   Server: Microsoft-IIS/7.5....
   Content-Type: application/json; charset=utf-8 <--good
   .....
   .....複製程式碼

原則4——在將不受信任的資料作為CSS屬性插入到文件之前一定要進行轉義

看下面的程式碼

<style>selector { property : ...將不受信任的資料轉義後再放在這...; } </style> 
屬性值

 <style>selector { property : "...將不受信任的資料轉義後再放在這..."; } </style>
屬性值

 <span style="property : ...將不受信任的資料轉義後再放在這...">text</span> 
屬性值複製程式碼

需要注意的是,還是有一些CSS屬性值對於“不受信任的”資料是無法確保萬無一失的——即使做了轉義,如下面的兩個CSS屬性:

{ background-url : "javascript:alert(1)"; }  
 { text-size: "expression(alert(`XSS`))"; }   // only in IE複製程式碼

你應該確保所有CSS屬性值引入的外部連結是由“http”開頭的,而不是“javascript”開頭的。

原則5——在向HTML的URL引數插入將不受信任的資料前,一定要將進行轉義

看下面的程式碼

<a href="http://www.somesite.com?test=...將不受信任的資料轉義後再放在這...">link</a >複製程式碼

加分原則1——對於cookie使用httpOnly標識

使用httpOnly標識後的cookie JavaScript是無法獲取的,又由於cookie是基於同源原則,所以一定程度上會防範那些利用客戶cookie的XSS攻擊。

加分原則2——在http header中使用Content Security Policy

利用http header中的屬性值Content-Security-Policy來防範XSS。HTTP 響應頭 Content-Security-Policy 允許站點管理者在指定的頁面控制使用者代理的資源。除了少數例外,這條政策將極大地指定服務源 以及指令碼端點。

加分原則3——使用自動轉義模板系統

許多Web應用程式框架提供了自動的上下文轉義功能,如AngularJS嚴格的上下文轉義Go模板。 儘可能使用這些技術。

加分原則4——在http header中使用X-XXS-Protection

HTTP X-XSS-Protection 響應頭是Internet Explorer,Chrome和Safari的一個功能,當檢測到跨站指令碼攻擊 (XSS)時,瀏覽器將停止載入頁面。雖然這些保護在現代瀏覽器中基本上是不必要的,當網站實施一個強大的Content-Security-Policy來禁用內聯的JavaScript (`unsafe-inline`)時, 他們仍然可以為尚不支援 CSP 的舊版瀏覽器的使用者提供保護。

總結

XSS攻擊的後果是不可估量的,而往往他又是容易被人忽視的。結合上面提到的幾點,檢查一下自己的Web App是否有上面的漏洞。

如果你堅持將全文都看完,你一定深愛著前端技術,那我覺得你有必要關注一下我的公眾號——較真的前端,在那裡會有更多的技術分享和前端乾貨等著你。

參考文章:
8大前端安全問題(上) – ThoughtWorks洞見 
Cross-site Scripting (XSS) 
XSS (Cross Site Scripting) Prevention Cheat Sheet

相關文章