XSS介紹
跨站腳本攻擊指的是自己的網(wǎng)站運(yùn)行了別的網(wǎng)站里面的代碼
攻擊原理是原本需要接受數(shù)據(jù)但是一段腳本放置在了數(shù)據(jù)中:
該攻擊方式能做什么者祖?
- 獲取頁(yè)面數(shù)據(jù)
- 獲取Cookies
- 劫持前端邏輯
- 發(fā)送請(qǐng)求到攻擊者自己的網(wǎng)站實(shí)現(xiàn)資料的盜取
- 偷取網(wǎng)站任意數(shù)據(jù)
- 偷取用戶密碼和登陸狀態(tài)
- 改變按鈕的邏輯
XSS攻擊類型
其實(shí)XSS的種類非常的多尤其是變種的特別多翰舌,大致可以分為兩種
反射型:是通過(guò)URL參數(shù)直接注入,一般是使用alert來(lái)探測(cè)站點(diǎn)是否防御,直接攻擊的使用src來(lái)引入自己的腳本
http://localhost:1521/?from=<script>alert(1)</script>bing
存儲(chǔ)型:存儲(chǔ)到DB后讀取時(shí)注入(危害很大)
在評(píng)論的時(shí)候?qū)憇cript標(biāo)簽,這樣數(shù)據(jù)就是存儲(chǔ)在數(shù)據(jù)庫(kù)中的,如果該頁(yè)面要讀取出這條有script標(biāo)簽的信息那么將這個(gè)網(wǎng)址發(fā)給別人別人也會(huì)中招驰贷。
XSS攻擊注入點(diǎn):
html節(jié)點(diǎn)內(nèi)容:如果一個(gè)節(jié)點(diǎn)是動(dòng)態(tài)生成的,有可能這個(gè)節(jié)點(diǎn)的數(shù)據(jù)有腳本(用戶輸入信息)
html屬性:某個(gè)html的屬性是由用戶輸入的洛巢,輸入的內(nèi)容可能有腳本
<img src="1" onerror="alert(1)"/>
1" onerror="alert(1) // src被提前關(guān)閉
js代碼:js代碼中存在后臺(tái)注入的變量或者用戶輸入的信息
localhost:1521/?from=google";alert(1);"
富文本:其實(shí)是一大段的html括袒,我們需要保留格式又要去掉script標(biāo)簽,這是比較麻煩的
富文本得保留HTML稿茉,HTML有XSS就有攻擊風(fēng)險(xiǎn)
實(shí)際上瀏覽器有著XSS的部分防御機(jī)制锹锰,可以通過(guò)
ctx.set('X-XSS-Protection',0); // 0-disable 1-enable
來(lái)進(jìn)行關(guān)閉,瀏覽器的防御很有限漓库,只能是反射型的參數(shù)并且出現(xiàn)在html節(jié)點(diǎn)和屬性中才會(huì)進(jìn)行防御恃慧,在js和富文本中是不會(huì)攔截的。
五種防御方式
HTML節(jié)點(diǎn)內(nèi)容的XSS防御
轉(zhuǎn)義掉<<和>> 即轉(zhuǎn)義掉<>即可渺蒿,轉(zhuǎn)義的時(shí)機(jī)有兩種痢士,一種是寫入數(shù)據(jù)庫(kù)的時(shí)候進(jìn)行轉(zhuǎn)義,另一種實(shí)在解析的時(shí)候進(jìn)行轉(zhuǎn)義茂装。
這里是在顯示的時(shí)候轉(zhuǎn)義
var escapeHtml = function(str){
str = str.replace(/>/g, '<');
str = str.replace(/>/g, '>');
return str;
}
escapeHtml(content);
HTML屬性的XSS防御
轉(zhuǎn)義”&quto; 即轉(zhuǎn)義掉雙引號(hào)怠蹂,'轉(zhuǎn)義掉單引號(hào)善延,(另一個(gè)要注意的是實(shí)際上html的屬性可以不包括引號(hào),因此嚴(yán)格的說(shuō)我們還需要對(duì)空格進(jìn)行轉(zhuǎn)義城侧,但是這樣會(huì)導(dǎo)致渲染的時(shí)候空格數(shù)不對(duì)易遣,因此我們不轉(zhuǎn)義空格,然后再寫html屬性的時(shí)候全部帶上引號(hào))這樣屬性就不會(huì)被提前關(guān)閉了
var escapeHtmlProperty = function(str){
str = str.replace(/"/g, '&quto;');
str = str.replace(/'/g, ''');
str = str.replace(/ /g, ' ');
return str;
}
escapeHtml(content);
其實(shí)以上這兩個(gè)函數(shù)可以合并成一個(gè)函數(shù)嫌佑,這樣不管是內(nèi)容還是屬性都可以使用一個(gè)函數(shù)來(lái)過(guò)濾了:
HTML轉(zhuǎn)義函數(shù)
var escapeHtmlProperty = function(str){
if(!str) return '';
str = str.replace(/&/g, '&');
str = str.replace(/>/g, '<');
str = str.replace(/>/g, '>');
str = str.replace(/"/g, '&quto;');
str = str.replace(/'/g, ''');
return str;
}
escapeHtml(content);
js轉(zhuǎn)義
轉(zhuǎn)義”\”或者替換成json
var escapeForJs = function(str){
if(!str) return '';
str = str.replace(/\\/g,'\\\\');
str = str.replace(/"/g,'\\"');
}
這里的解決方式并不完整豆茫,因?yàn)檫€有可能是單引號(hào)或者其他形勢(shì)包裹的,這里最保險(xiǎn)的方法其實(shí)很簡(jiǎn)單屋摇,就是對(duì)數(shù)據(jù)做一次JSON.stringify即可
富文本
由于需要完整的HTML因此不太容易過(guò)濾澜薄,一般是按照白名單進(jìn)行保留部分標(biāo)簽和屬性來(lái)進(jìn)行過(guò)濾,除了允許的標(biāo)簽和屬性摊册,其他的全部不允許(也有黑名單的方式,但是由于html復(fù)雜效果比較差颊艳,原理就是之前的正則替換)
其實(shí)可以用別人寫好的XSS組件就叫做xss茅特,直接
npm install xss
白名單-使用第三方庫(kù)XSS,支持指定白名單
var xssFilter = function(html){
if(!html) return '';
var xss = require('xss');
var ret = xss(html, {
whiteList:{
img: ['src'],
a: ['href'],
font: ['size', 'color']
},
onIgnoreTag: function(){
return '';
}
});
console.log(html, ret);
return ret;
};
本文作者熊冰棋枕,個(gè)人網(wǎng)站Bing的天涯路白修,轉(zhuǎn)載請(qǐng)注明出處。