編者說:作為JS系工程師接觸最多的漏洞我想就是 XSS 漏洞了,然鵝并不是所有的同學對其都有一個清晰的認識。今天我們請來了@盧士傑 同學為我們分享他眼中的 XSS 漏洞攻擊,希望能幫助到大家。
什麼是 XSS 攻擊
XSS(Cross-Site Scripting)又稱跨站腳本,XSS的重點不在于跨站點,而是在于腳本的執行。XSS是一種經常出現在 Web 應用程式中的計算機安全漏洞,是由于 Web 應用程式對使用者的輸入過濾不足而産生的。
常見的 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 破壞頁面正常的結構與樣式等;
防禦方法
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 前端安全意識。
參考文檔
● http://www.qa-knowhow.com/?p=1467
● https://brajeshwar.github.io/entities/
● https://excess-xss.com/
● https://github.com/chrisisbeef/jquery-encoder
原文釋出時間為:2018-11-23
本文來自雲栖社群合作夥伴“
前端大學”,了解相關資訊可以關注“
”。