XSS***全稱跨站腳本***,是爲不和層疊樣式表(Cascading Style Sheets, CSS)的縮寫混淆,故將跨站腳本***縮寫爲XSS,XSS是一種在web應用中的計算機安全漏洞,它允許惡意web用戶將代碼植入到提供給其它用戶使用的頁面中。
一、XSS ***
常見的XSS***有三種:反射型、DOM-based 型、存儲型。其中反射型、DOM-based 型可以歸類爲非持久型XSS***,存儲型歸類爲持久型XSS***。
1、反射型
反射型XSS一般是***者通過特定手法(如電子郵件),誘使用戶去訪問一個包含惡意代碼的URL,當受害者點擊這些專門設計的鏈接的時候,惡意代碼會直接在受害者主機上的瀏覽器執行。
對於訪問者而言是一次性的,具體表現在我們把我們的惡意腳本通過URL 的方式傳遞給了服務器,而服務器則只是不加處理的把腳本“反射”回訪問者的瀏覽器而使訪問者的瀏覽器執行相應的腳本。反射型XSS的觸發有後端的參與,要避免反射性XSS,必須需要後端的協調,後端解析前端的數據時首先做相關的字串檢測和轉義處理。
此類XSS通常出現在網站的搜索欄、用戶登錄口等地方,常用來竊取客戶端Cookies 或進行釣魚欺騙。
2、DOM-based 型
客戶端的腳本程序可以動態地檢查和修改頁面內容,而不依賴於服務器端的數據。例如客戶端如從URL 中提取數據並在本地執行,如果用戶在客戶端輸入的數據包含了惡意的JavaScript 腳本,而這些腳本沒有經過適當的過濾和消毒,那麼應用程序就可能受到DOM-based XSS***。需要特別注意以下的用戶輸入document.URL、 location.hash、 location.search、 document.referrer 等。
3、存儲型
***者事先將惡意代碼上傳或儲存到漏洞服務器中,只要受害者瀏覽包含此惡意代碼的頁面就會執行惡意代碼。這就意味着只要訪問了這個頁面的訪客,都有可能會執行這段惡意腳本,因此儲存型XSS的危害會更大。
存儲型XSS一般出現在網站留言、評論、博客日誌等交互處,惡意腳本存儲到客戶端或者服務端的數據庫中。
二、XSS ***的危害
XSS可以導致:
(1)***劫持訪問;
(2)盜用cookie 實現無密碼登錄;
(3)配合csrf ***完成惡意請求;
(4)使用js 或css 破壞頁面正常的結構與樣式等。
三、XSS ***防禦方法
1、XSS 防禦之HTML 編碼
應用範圍:將不可信數據放入到HTML 標籤內(例如div、span等)的時候進行HTML編碼。
編碼規則:將& < > " ' / 轉義爲實體字符(或者十進制、十六進制)。
示例代碼:
function encodeForHTML ( str , kwargs ){
return ( '' + str )
. replace ( /&/ g , '&' )
. replace ( /</ g , '<' ) // DEC=> < HEX=> < Entity=> <
. replace ( />/ g , '>' )
. replace ( /"/ g , '"' )
. replace ( /'/ g , ''') // ' 不推薦,因爲它不在 HTML 規範中
. replace ( /// g , '/' );
};
HTML 有三種編碼表現方式:十進制、十六進制、命名實體。例如小於號(<)可以編碼爲"十進制> <", "十六進制=> <", "命名實體=> <" 三種方式。對於單引號(')由於實體字符編碼方式不在HTML 規範中,所以此處使用了十六進制編碼。
2、XSS 防禦之HTML Attribute 編碼
應用範圍:將不可信數據放入HTML 屬性時(不含src、href、style 和事件處理屬性),進行HTML Attribute 編碼。
編碼規則:除了字母數字字符以外,使用HH;(或者可用的命名實體)格式來轉義ASCII值小於256所有的字符。
示例代碼:
function encodeForHTMLAttibute ( str , kwargs ){
let encoded = '' ;
for ( let i = 0 ; i < str . length ; i ++) {
let ch = hex = str [ i ];
if (!/[ A - Za - z0 - 9 ]/. test ( str [ i ]) && str . charCodeAt ( i ) < 256 ) {
hex = '&#x' + ch . charCodeAt ( 0 ). toString ( 16 ) + ';' ;
}
encoded += hex ;
}
return encoded ;
};
3、XSS 防禦之JavaScript 編碼
作用範圍:將不可信數據放入事件處理屬性、JavaScirpt值時進行JavaScript 編碼。
編碼規則:除字母數字字符外,請使用xHH格式轉義ASCII碼小於256的所有字符。
示例代碼:
function encodeForJavascript ( str , kwargs ) {
let encoded = '' ;
for ( let i = 0 ; i < str . length ; i ++) {
let cc = hex = str [ i ];
if (!/[ A - Za - z0 - 9 ]/. test ( str [ i ]) && str . charCodeAt ( i ) < 256 ) {
hex = '\x' + cc . charCodeAt (). toString ( 16 );
}
encoded += hex ;
}
return encoded ;
};
4、XSS 防禦之URL 編碼
作用範圍:將不可信數據作爲URL 參數值時需要對參數進行URL 編碼。
編碼規則:將參數值進行encodeURIComponent 編碼。
示例代碼:
function encodeForURL ( str , kwargs ){
return encodeURIComponent ( str );
};
5、XSS 防禦之CSS 編碼
作用範圍:將不可信數據作爲CSS 時進行CSS 編碼。
編碼規則:除了字母數字字符以外,使用XXXXXX格式來轉義ASCII值小於256的所有字符。
示例代碼:
function encodeForCSS ( attr , str , kwargs ){
let encoded = '' ;
for ( let i = 0 ; i < str . length ; i ++) {
let ch = str . charAt ( i );
if (! ch . match ( /[a-zA-Z0-9]/ ) {
let hex = str . charCodeAt ( i ). toString ( 16 );
let pad = '000000' . substr (( hex . length ));
encoded += '\' + pad + hex ;
} else {
encoded += ch ;
}
}
return encoded ;
};
四、結語
在任何時候用戶的輸入都是不可信的。對於HTTP 參數,理論上都要進行驗證,例如某個字段是枚舉類型,其就不應該出現枚舉以爲的值;對於不可信數據的輸出要進行相應的編碼;此外 httpOnly、 CSP、 X-XSS-Protection、 Secure Cookie等也可以起到有效的防護。
XSS漏洞有時比較難發現,所幸當下React、Vue等框架都從框架層面引入了XSS防禦機制,一定程度上解放了我們的雙手。
但是作爲開發人員依然要了解XSS基本知識、於細節處避免製造XSS漏洞。框架是輔助,我們仍需以人爲本,規範開發習慣,提高Web 前端安全意識。