前端的安全攻擊主要有4種類型:XSS突诬, CSRF,SQL Injection芜繁,Client-state manipulation旺隙。
限于內(nèi)容太多,我會寫一個系列骏令。這篇為該系列的第一篇:XSS蔬捷。
接下來的內(nèi)容主要包括4方面:
- 什么是XSS
- XSS的分類
- 每一類XSS的手法
- 應(yīng)對XSS的辦法
話不多說,我們現(xiàn)在就進(jìn)入正題榔袋。
什么是XSS
一句話解釋XSS就是:攻擊者通過代碼注入(code injection)的方式周拐,惡意篡改受害者所訪問的網(wǎng)站內(nèi)容;把受害者引導(dǎo)到惡意網(wǎng)站凰兑;竊取受害者cookie從未假冒受害者身份等的一種前端安全攻擊技術(shù)妥粟。
XSS的分類
大家可能從上面的解釋里面也看出來了,受害者可能會遭遇到不同類型的攻擊吏够;同樣的XSS的攻擊手法也是“豐富多彩”勾给,現(xiàn)在就讓我們來看一下XSS都有哪些經(jīng)典的手法:
其中Stored XSS也叫做persistent XSS,它是一種持久性的XSS锅知。Reflected XSS也叫做non-persistent XSS播急,非持久性XSS。
持久性的XSS是什么意思售睹?為什么Stored XSS是持久性的旅择,而Reflected XSS是非持久性的?
接下來我們通過展示以上三類不同的XSS的攻擊手法侣姆,來回答上面的問題生真。
Stored XSS
話說“一圖勝千言”沉噩, 我們先看一下Stored XSS的過程:
為了便于大家理解,我們假定被攻擊的網(wǎng)站名字叫:abc柱蟀。
受害者的名字叫:lancer
step1: 攻擊者訪問網(wǎng)站abc川蒙,提交了一個包含惡意代碼的評論數(shù)據(jù)。網(wǎng)站abc處理這個post請求长已,把這個評論存進(jìn)數(shù)據(jù)庫畜眨。
step2: 一個無辜的用戶(也就是我們的被害者lancer)訪問網(wǎng)站abc,到了有評論的頁面术瓮,所以發(fā)起了一個對評論的GET請求康聂。
step3: 網(wǎng)站abc接收到lancer的請求扶叉,于是從數(shù)據(jù)庫取出評論放到html頁面里员串,把這個包含評論的頁面返回給lancer的瀏覽器。lancer的瀏覽器接收到返回的頁面再芋,開始解析代碼辜伟。只是氓侧,不幸的是,這條評論不是一般的text导狡,而是一段js代碼约巷。
step4: 我們現(xiàn)在來耐心地分析一下這段js代碼做了什么事情:
- 通過document.cookie讀取了lancer的cookie(cookie里面包含lancer的用戶信息)
- 通過window.location="http://attacker/..." 跳轉(zhuǎn)到攻擊者自己的網(wǎng)站
于是,攻擊者通過這種手段旱捧,竊取了被害者的cookie独郎。
Stored XSS的危害性在于:
- 攻擊范圍廣:只要訪問評論頁面的用戶都會受害
- 持續(xù)性:因?yàn)檫@段有害的代碼被存入了數(shù)據(jù)庫
所以,看到這里枚赡,也就解答了我們開篇的問題:為什么說Stored XSS是持續(xù)性的囚聚。
Reflected XSS
Reflected XSS于Stored XSS有相似之處,但是最大的不同在于通過Reflected XSS所收到的惡意代碼标锄,不會被網(wǎng)站abc存入數(shù)據(jù)庫。
Reflected XSS還有一個特點(diǎn)茁计,受害者是特定的料皇。而Stored XSS的受害者不是特定的,因?yàn)榉彩窃L問含有惡意代碼的頁面星压,都會收到傷害践剂,攻擊者并并不知道哪些人會去訪問這個頁面。
我們也還是先來看圖解:
step1:攻擊者通過郵件娜膘,短信等方式給選定的受害者們發(fā)送含有惡意代碼的網(wǎng)站鏈接逊脯。誘使受害者點(diǎn)擊這條鏈接。比如竣贪,受害者之一的lancer就在某一天收到了這封郵件军洼。
step2:lancer點(diǎn)擊了這條惡意鏈接巩螃,向網(wǎng)站abc發(fā)起了一條GET請求。
step3:被攻擊的網(wǎng)站abc收到了lancer的請求匕争,從url query里面取出keyword寫入到頁面避乏,向lancer返回頁面代碼。lancer的瀏覽器接收到返回的頁面甘桑,開始解析代碼拍皮。只是,依然不幸的是跑杭,這條評論不是一般的text铆帽,而是一段js代碼。
step4:和Stored XSS一樣德谅,惡意代碼被執(zhí)行爹橱,攻擊者獲取到了lancer的cookie。
對比一下Store XSS女阀,Reflected XSS與之最大的差別是:
- 被害者是特定的宅荤。
- 惡意代碼不會被存入數(shù)據(jù)庫
Dom-based XSS
Dom-based XSS具備Stored XSS或者Reflected XSS的特征,但是在此之上浸策,又衍生出一些差別冯键。我們現(xiàn)在來看一個具備Reflected XSS特征的Dom-based XSS的圖解過程來了解一下Dom-based XSS的特點(diǎn):
step1:攻擊者通過郵件,短信等方式給選定的受害者們發(fā)送含有惡意代碼的網(wǎng)站鏈接庸汗。誘使受害者點(diǎn)擊這條鏈接惫确。比如,受害者之一的lancer就在某一天收到了這封郵件蚯舱。
step2:lancer點(diǎn)擊了這條惡意鏈接改化,向網(wǎng)站abc發(fā)起了一條GET請求。
step3:被攻擊的網(wǎng)站abc收到了lancer的請求枉昏,從url query里面取出keyword陈肛。與reflected xss不同的是,這里不是直接把keyword展示在頁面上兄裂。而是作為H3的innerHtml句旱。代碼組裝完畢,向lancer的瀏覽器返回response代碼晰奖。
step4:lancer的瀏覽器接收到abc返回的代碼谈撒,開始解析代碼。與reflect xss不同的是匾南,在這一步會先執(zhí)行我們無害的javaScript代碼啃匿,也就是
<script>
let keyword = request.query[keyword]
document.querySelector(‘h3’).innerHTML = keyword
</script>
這段代碼本身不具備攻擊型,但是因?yàn)槲覀儼裬eyword(取出來是一段惡意JavaScript代碼)作為H3的innerHTML,所以這段惡意代碼會被執(zhí)行溯乒。所以才造成了網(wǎng)站abc會受到攻擊夹厌。
step5:惡意代碼被執(zhí)行,加入這段惡意代碼包含的是竊取用戶的cookie橙数,那么就會和前面的xss一樣尊流,用戶存在cookie里面的敏感信息被發(fā)送到了攻擊者的服務(wù)器。
那么灯帮,Dom-based XSS它的特殊危害性是崖技?
- 它對server是不可見的。對比Stored XSS和Reflected XSS钟哥,惡意代碼的內(nèi)容在server端組裝的時候迎献,不可見。因?yàn)椴豢梢娔宸。敲次覀兙筒荒茉趕erver端對它做一定的處理(后面我們會講到怎樣在server端處理XSS)吁恍。這樣,就把我們的惡意代碼推到客戶端(也就是用戶的瀏覽器)去了播演。
Ok冀瓦,以上就是對三種XSS的介紹。相信大家已經(jīng)對他們的特性和工作原理有了一定的了解写烤。接下來翼闽,就進(jìn)入到今天這篇文章的核心:怎樣應(yīng)對XSS。
應(yīng)對XSS的辦法
應(yīng)對XSS的辦法 - How
基本說來洲炊,處理XSS的辦法主要有2種:
- Encoding(編碼):把可運(yùn)行的惡意代碼編碼成不可運(yùn)行的單純的數(shù)據(jù)感局。
- Validation(驗(yàn)證):過濾出惡意代碼,隨后可以對其直接拋棄暂衡,或者處理成飛惡意代碼(消毒)询微。
應(yīng)對XSS的辦法 - What
但是,到底該采取哪種手法狂巢,依賴于不同的上下文撑毛。請看上圖的第二列(what的這一列)。一般來說唧领,一個數(shù)據(jù)(比如用戶輸入的數(shù)據(jù))可能會被用到4種情況:
- 1 元素內(nèi)容:<div>{userInput}</div>
- 2 元素的屬性:<a href={userInput}></a>
- 3 URL的query:http://abc.com/xxx?search={userInput}
- 4 CSS值:color: {userInput}
應(yīng)對XSS的辦法 - When
假如我們收到用戶提交的數(shù)據(jù)藻雌,是否在存入數(shù)據(jù)庫,甚至是前端拿到用戶的數(shù)據(jù)在往server提交之前疹吃,就應(yīng)該對惡意代碼進(jìn)行處理呢?
但是事實(shí)是西雀,通常不會也不能這么做萨驶。因?yàn)椋腿缥覀冊谏厦嬷v到艇肴,用戶提交的數(shù)據(jù)可能會被使用到不同的場景腔呜,不同的場景不同的處理方式是不一樣叁温;甚至,同一個數(shù)據(jù)核畴,可能會在不同的場景下使用膝但。所以,在拿到數(shù)據(jù)之后就處理谤草,不應(yīng)該是我們主要處理數(shù)據(jù)的時機(jī)跟束。
相反的,在把數(shù)據(jù)render到HTML的時候丑孩,對數(shù)據(jù)進(jìn)行處理冀宴,應(yīng)該是我們主要的處理時機(jī)。
應(yīng)對XSS的辦法 - Where
前面我們講到XSS類型的時候温学,我們說到對于Stored XSS和Reflected XSS來說略贮,惡意代碼是對server端可見的,這就意味著我們可以在server端處理XSS仗岖;但是DOM-based XSS是對server端不可見的逃延,所以我們得在客戶端處理XSS。所以轧拄,綜合下來揽祥,我們既需要在server端也需要在客戶端處理XSS。
在server端紧帕,當(dāng)然是使用在server端使用的語言對XSS進(jìn)行處理盔然;在客戶端,通常就是JavaScript是嗜。
應(yīng)對XSS的具體手法 - server端Encoding(編碼)
Encoding(編碼)愈案,就是把可運(yùn)行的代碼(code)編碼成不可運(yùn)行的單純的數(shù)據(jù)。例如鹅搪,假如我們收到一段用戶提交的js代碼:
<script>.....</script>
我們可以通過編碼規(guī)則站绪,把"<" ">"編碼。經(jīng)編碼之后丽柿,上面的代碼恢准,就不再是一段可執(zhí)行的代碼,而只是text甫题。例如馁筐,下圖列了一些html的編碼:
應(yīng)對XSS的具體手法 - client端Encoding(編碼)
客戶端的編碼,主要依賴于JavaScript提供的API坠非。如上圖所示敏沉,則是我們應(yīng)對4種不同的情況下的編碼手法。
對于,一些具體的情況盟迟,比如一個輸入用戶名的input秋泳,因?yàn)槲覀冎缹τ谝粋€用戶名的input,我們只能接受字母攒菠,數(shù)字迫皱,下劃線。那么辖众,類似于這種情況卓起,我們就可以對用戶的輸入進(jìn)行validation(驗(yàn)證)。
應(yīng)對XSS的具體手法 - validation(驗(yàn)證)
驗(yàn)證赵辕,就是對我們接收到的數(shù)據(jù)進(jìn)行過濾既绩,過濾出惡意代碼,得到合法代碼还惠。如下圖所示:
具體到執(zhí)行驗(yàn)證之前饲握,我們需要考慮2點(diǎn):
- 分類策略:是采用黑名單還是白名單來做驗(yàn)證
-
驗(yàn)證結(jié)果的處理:過濾出來的惡意代碼,是直接拋棄蚕键,還是處理成合法代碼
驗(yàn)證前需要考慮的事項(xiàng)
驗(yàn)證的分類策略 - 黑名單
黑名單救欧,即列舉了惡意代碼類型的名單。如果數(shù)據(jù)在黑名單里面锣光,則被判定為非法代碼笆怠;否則為合法代碼。
黑名單有著一些缺陷誊爹。因?yàn)楝F(xiàn)實(shí)是復(fù)雜的蹬刷,攻擊者的手法是千奇百怪的,要創(chuàng)建一個包含所有可能的惡意代碼的黑名單频丘,往往是困難办成,甚至是不能的。
再者搂漠,世界是變化的迂卢,XSS的手法也是日新月異的。某天桐汤,一種不曾包含在黑名單里面的新的XSS出現(xiàn)了而克,那這份黑名單就不能有效地抵御這次攻擊。
驗(yàn)證的分類策略 - 白名單
與黑名單相反怔毛,白名單是包含了合法代碼的名單员萍。通常來說,合法的情況是可以窮盡的拣度,比如一個輸入用戶名的input碎绎,我就只接受字母蜂莉,數(shù)字,下劃線這三種類型的字符混卵。
白名單的有效性也是長的。因?yàn)椴徽撌欠裼行碌腦SS產(chǎn)生窖张,但是對于我的業(yè)務(wù)來說幕随,我所接受的數(shù)據(jù)類型沒有變化,我依然只會取出符合我白名單規(guī)則的數(shù)據(jù)宿接。
所以赘淮,當(dāng)我們選擇驗(yàn)證策略的時候,要盡量地選用白名單睦霎。
驗(yàn)證結(jié)果處理 - 舍棄
當(dāng)我們檢測出用戶的輸入里面包含惡意代碼的時候梢卸,直接舍棄掉這一條數(shù)據(jù),這條數(shù)據(jù)不會出現(xiàn)在網(wǎng)站的任何地方副女,即叫做舍棄蛤高。
例如,有一個需要用戶輸入信用卡號碼的input碑幅,用戶不僅輸入了數(shù)字戴陡,還輸入了連接線(用戶出于習(xí)慣)。我們直接舍棄這條數(shù)據(jù)沟涨,把這條數(shù)據(jù)判定為不合法恤批。當(dāng)然,相應(yīng)地裹赴,你會給用戶返回一個錯誤提醒喜庞。
驗(yàn)證結(jié)果處理 - 消毒
當(dāng)我們檢測出用戶的輸入里面包含惡意代碼的時候,經(jīng)過一定的處理方式棋返,去掉惡意的部分延都,留下合法的代碼,即叫做消毒懊昨。
還是用戶輸入信用卡號碼的例子窄潭。對比舍棄的做法,消毒的做法是允許用戶輸入連接線酵颁,只是我們拿到數(shù)據(jù)之后嫉你,把連接線給去掉,最后得到只包含數(shù)字的信用卡號碼躏惋。