XSS攻擊
什么是 XSS
Cross-Site Scripting
(跨站腳本攻擊)簡稱XSS
拔妥,是一種代碼注入攻擊薪者。攻擊者通過在目標(biāo)網(wǎng)站上注入惡意腳本斯棒,使之在用戶的瀏覽器上運(yùn)行许帐。利用這些惡意腳本劳坑,攻擊者可獲取用戶的敏感信息如Cookie
投蝉、SessionID
等窍株,進(jìn)而危害數(shù)據(jù)安全这揣。
所以,網(wǎng)頁上哪些部分會引起XSS
攻擊?簡單來說,任何可以輸入的地方都有可能引起,包括URL
XSS 常見的注入方法:
- 在
HTML
中內(nèi)嵌的文本中穗酥,惡意內(nèi)容以script
標(biāo)簽形成注入。 - 在內(nèi)聯(lián)的
JavaScript
中框仔,拼接的數(shù)據(jù)突破了原本的限制(字符串舀武,變量,方法名等)离斩。 - 在標(biāo)簽屬性中银舱,惡意內(nèi)容包含引號,從而突破屬性值的限制跛梗,注入其他屬性或者標(biāo)簽寻馏。
- 在標(biāo)簽的
href
、src
等屬性中核偿,包含javascript:
(偽協(xié)議)等可執(zhí)行代碼诚欠。 - 在
onload
、onerror
漾岳、onclick
等事件中轰绵,注入不受控制代碼。 - 在
style
屬性和標(biāo)簽中尼荆,包含類似background-image:url("javascript:...");
的代碼(新版本瀏覽器已經(jīng)可以防范)藏澳。 - 在
style
屬性和標(biāo)簽中,包含類似expression(...)
的 CSS 表達(dá)式代碼(新版本瀏覽器已經(jīng)可以防范)耀找。
XSS 攻擊的分類
根據(jù)攻擊的來源翔悠,
XSS
攻擊可分為存儲型、反射型和DOM
型三種野芒。
存儲型 XSS
存儲型
XSS
的攻擊步驟:
- 攻擊者將惡意代碼提交到目標(biāo)網(wǎng)站的數(shù)據(jù)庫中蓄愁。
- 用戶打開目標(biāo)網(wǎng)站時,網(wǎng)站服務(wù)端將惡意代碼從數(shù)據(jù)庫取出狞悲,拼接在
HTML
中返回給瀏覽器撮抓。- 用戶瀏覽器接收到響應(yīng)后解析執(zhí)行,混在其中的惡意代碼也被執(zhí)行摇锋。
- 惡意代碼竊取用戶數(shù)據(jù)并發(fā)送到攻擊者的網(wǎng)站丹拯,或者冒充用戶的行為,調(diào)用目標(biāo)網(wǎng)站接口執(zhí)行攻擊者指定的操作荸恕。
- 存儲型XSS (又被稱為持久性XSS)攻擊常見于帶有用戶保存數(shù)據(jù)的網(wǎng)站功能乖酬,如論壇發(fā)帖、商品評論融求、用戶私信等咬像。
- 它是最危險的一種跨站腳本,相比反射型XSS和DOM型XSS具有更高的隱蔽性,所以危害更大县昂,因?yàn)?strong>它不需要用戶手動觸發(fā)肮柜。任何允許用戶存儲數(shù)據(jù)的web程序都可能存在存儲型XSS漏洞,當(dāng)攻擊者提交一段XSS代碼后倒彰,被服務(wù)器端接收并存儲审洞,當(dāng)所有瀏覽者訪問某個頁面時都會被XSS。
反射型 XSS
反射型
XSS
的攻擊步驟:
- 攻擊者構(gòu)造出特殊的
URL
待讳,其中包含惡意代碼预明。- 用戶打開帶有惡意代碼的
URL
時,網(wǎng)站服務(wù)端將惡意代碼從URL
中取出耙箍,拼接在HTML
中返回給瀏覽器撰糠。- 用戶瀏覽器接收到響應(yīng)后解析執(zhí)行,混在其中的惡意代碼也被執(zhí)行辩昆。
- 惡意代碼竊取用戶數(shù)據(jù)并發(fā)送到攻擊者的網(wǎng)站阅酪,或者冒充用戶的行為,調(diào)用目標(biāo)網(wǎng)站接口執(zhí)行攻擊者指定的操作汁针。
反射型 XSS
跟存儲型 XSS
的區(qū)別是:存儲型 XSS
的惡意代碼存在數(shù)據(jù)庫里术辐,反射型XSS
的惡意代碼存在 URL 里。
- 反射型XSS (也被稱為非持久性XSS)漏洞常見于通過URL傳遞參數(shù)的功能施无,如網(wǎng)站搜索辉词、跳轉(zhuǎn)等。
由于需要用戶主動打開惡意的URL 才能生效猾骡,攻擊者往往會結(jié)合多種手段誘導(dǎo)用戶點(diǎn)擊瑞躺。 - POST 的內(nèi)容也可以觸發(fā)反射型XSS,只不過其觸發(fā)條件比較苛刻(需要構(gòu)造表單提交頁面兴想,并引導(dǎo)用戶點(diǎn)擊)幢哨,所以非常少見。
DOM 型 XSS
DOM
型XSS
的攻擊步驟:
- 攻擊者構(gòu)造出特殊的
URL
嫂便,其中包含惡意代碼捞镰。- 用戶打開帶有惡意代碼的
URL
。- 用戶瀏覽器接收到響應(yīng)后解析執(zhí)行毙替,前端
JavaScript
取出URL
中的惡意代碼并執(zhí)行岸售。- 惡意代碼竊取用戶數(shù)據(jù)并發(fā)送到攻擊者的網(wǎng)站,或者冒充用戶的行為厂画,調(diào)用目標(biāo)網(wǎng)站接口執(zhí)行攻擊者指定的操作凸丸。
DOM
型XSS
跟前兩種 XSS
的區(qū)別:DOM
型 XSS
攻擊中,取出和執(zhí)行惡意代碼由瀏覽器端完成木羹,屬于前端 JavaScript
自身的安全漏洞甲雅,而其他兩種 XSS
都屬于服務(wù)端的安全漏洞。
注意:
DOM
通常代表在html
坑填、xhtml
和xml
中的對象抛人,使用DOM
可以允許程序和腳本動態(tài)的訪問和更新文檔的內(nèi)容、結(jié)構(gòu)和樣式脐瑰。它不需要服務(wù)器解析響應(yīng)的直接參與妖枚,觸發(fā)XSS
靠的是瀏覽器端的DOM
解析,所以防范DOM
型XSS
完全就是前端的責(zé)任,必須注意!!!苍在。
對比:
類型 | 存儲區(qū) | 插入點(diǎn) |
---|---|---|
存儲型 XSS | 后端數(shù)據(jù)庫 | HTML |
反射型 XSS | URL | HTML |
DOM 型 XSS | 后端數(shù)據(jù)庫/前端存儲/URL | 前端 JavaScript |
防御XSS
只要有輸入數(shù)據(jù)的地方绝页,就可能存在
XSS
危險。
常用防范方法
httpOnly: 在 cookie 中設(shè)置 HttpOnly 屬性后寂恬,js腳本將無法讀取到 cookie 信息续誉。
輸入過濾: 一般是用于對于輸入格式的檢查,例如:郵箱初肉,電話號碼酷鸦,用戶名,密碼……等牙咏,按照規(guī)定的格式輸入臼隔。不僅僅是前端負(fù)責(zé),后端也要做相同的過濾檢查妄壶。因?yàn)楣粽咄耆梢岳@過正常的輸入流程摔握,直接利用相關(guān)接口向服務(wù)器發(fā)送設(shè)置。
轉(zhuǎn)義 HTML: 如果拼接 HTML 是必要的丁寄,就需要對于引號氨淌,尖括號,斜杠進(jìn)行轉(zhuǎn)義,但這還不是很完善.想對 HTML 模板各處插入點(diǎn)進(jìn)行充分的轉(zhuǎn)義,就需要采用合適的轉(zhuǎn)義庫.(可以看下這個庫,還是中文的)
function escape(str) {
str = str.replace(/&/g, '&')
str = str.replace(/</g, '<')
str = str.replace(/>/g, '>')
str = str.replace(/"/g, '&quto;')
str = str.replace(/'/g, ''')
str = str.replace(/`/g, '`')
str = str.replace(/\//g, '/')
return str
}
- 白名單: 對于顯示富文本來說伊磺,不能通過上面的辦法來轉(zhuǎn)義所有字符宁舰,因?yàn)檫@樣會把需要的格式也過濾掉。這種情況通常采用白名單過濾的辦法奢浑,當(dāng)然也可以通過黑名單過濾蛮艰,但是考慮到需要過濾的標(biāo)簽和標(biāo)簽屬性實(shí)在太多,更加推薦使用白名單的方式雀彼。
預(yù)防存儲型和反射型 XSS 攻擊
存儲型和反射型
XSS
都是在服務(wù)端取出惡意代碼后壤蚜,插入到響應(yīng)HTML
里的,攻擊者刻意編寫的“數(shù)據(jù)”被內(nèi)嵌到“代碼”中徊哑,被瀏覽器所執(zhí)行袜刷。
預(yù)防這兩種漏洞,有兩種常見做法:
- 改成純前端渲染莺丑,把代碼和數(shù)據(jù)分隔開著蟹。
- 對
HTML
做充分轉(zhuǎn)義墩蔓。
HTML轉(zhuǎn)義前面已經(jīng)說過,這里僅僅談?wù)劶兦岸虽秩?/p>
純前端渲染的過程:
- 瀏覽器先加載一個靜態(tài)
HTML
,此HTML
中不包含任何跟業(yè)務(wù)相關(guān)的數(shù)據(jù)萧豆。- 然后瀏覽器執(zhí)行
HTML
中的JavaScript
奸披。JavaScript
通過Ajax
加載業(yè)務(wù)數(shù)據(jù),調(diào)用DOM API
更新到頁面上涮雷。
- 在純前端渲染中阵面,我們會明確的告訴瀏覽器:下面要設(shè)置的內(nèi)容是文本(.innerText),還是屬性(.setAttribute)洪鸭,還是樣式(.style)等等样刷。瀏覽器不會被輕易的被欺騙,執(zhí)行預(yù)期外的代碼了览爵。
- 但純前端渲染還需注意避免
DOM
型XSS
漏洞(例如 onload 事件和 href中的javascript:xxx 等置鼻,請參考下文”預(yù)防 DOM 型 XSS 攻擊“部分)。 - 在很多內(nèi)部蜓竹、管理系統(tǒng)中沃疮,采用純前端渲染是非常合適的。但對于性能要求高梅肤,或有
SEO
需求的頁面司蔬,我們?nèi)匀灰鎸ζ唇?code>HTML 的問題,這時就需要對HTML
進(jìn)行充分的轉(zhuǎn)義。
預(yù)防 DOM 型 XSS 攻擊
DOM
型XSS
攻擊姨蝴,實(shí)際上就是網(wǎng)站前端JavaScript
代碼本身不夠嚴(yán)謹(jǐn)俊啼,把不可信的數(shù)據(jù)當(dāng)作代碼執(zhí)行了。
- 在使用
.innerHTML
左医、.outerHTML
授帕、document.write()
時要特別小心,不要把不可信的數(shù)據(jù)作為HTML
插到頁面上浮梢,而應(yīng)盡量使用.textContent
跛十、.setAttribute()
等。 - 如果用 Vue/React 技術(shù)棧秕硝,并且不使用
v-html
/dangerouslySetInnerHTML
功能芥映,就在前端render
階段避免innerHTML
、outerHTML
的XSS
隱患远豺。 -
DOM
中的內(nèi)聯(lián)事件監(jiān)聽器奈偏,如location
、onclick
躯护、onerror
惊来、onload
、onmouseover
等棺滞,<a>
標(biāo)簽的href
屬性裁蚁,JavaScript
的eval()
矢渊、setTimeout()
、setInterval()
等枉证,都能把字符串作為代碼運(yùn)行矮男。如果不可信的數(shù)據(jù)拼接到字符串中傳遞給這些API
,很容易產(chǎn)生安全隱患刽严,請務(wù)必避免昂灵。
<!-- 內(nèi)聯(lián)事件監(jiān)聽器中包含惡意代碼 -->
<img onclick="UNTRUSTED" onerror="UNTRUSTED" src="data:image/png,">
<!-- 鏈接內(nèi)包含惡意代碼 -->
<a href="UNTRUSTED">1</a>
<script>
// setTimeout()/setInterval() 中調(diào)用惡意代碼
setTimeout("UNTRUSTED")
setInterval("UNTRUSTED")
// location 調(diào)用惡意代碼
location.href = 'UNTRUSTED'
// eval() 中調(diào)用惡意代碼
eval("UNTRUSTED")
</script>
CSRF 跨站點(diǎn)請求偽造
什么是 CSRF
跨站請求偽造(英語:Cross-site request forgery)避凝,也被稱為
one-click attack
或者session riding
舞萄,通常縮寫為CSRF
或者XSRF
管削, 是一種挾制用戶在當(dāng)前已登錄的Web
應(yīng)用程序上執(zhí)行非本意的操作的攻擊方法倒脓。如:攻擊者誘導(dǎo)受害者進(jìn)入第三方網(wǎng)站,在第三方網(wǎng)站中含思,向被攻擊網(wǎng)站發(fā)送跨站請求崎弃。利用受害者在被攻擊網(wǎng)站已經(jīng)獲取的注冊憑證,繞過后臺的用戶驗(yàn)證含潘,達(dá)到冒充用戶對被攻擊的網(wǎng)站執(zhí)行某項(xiàng)操作的目的饲做。
CSRF攻擊流程
下圖引自這位大佬的淺談CSRF攻擊方式,感謝!
從上圖可以看出,要完成一次CSRF攻擊遏弱,受害者必須依次完成兩個步驟:
- 1.登錄受信任網(wǎng)站A盆均,并在本地生成Cookie。
- 2.在不登出A的情況下漱逸,訪問危險網(wǎng)站B泪姨。
看到這里,你也許會說:“如果我不滿足以上兩個條件中的一個饰抒,我就不會受到CSRF的攻擊”肮砾。是的,確實(shí)如此袋坑,但你不能保證以下情況不會發(fā)生:
- 1.你不能保證你登錄了一個網(wǎng)站后仗处,不再打開一個tab頁面并訪問另外的網(wǎng)站。
- 2.你不能保證你關(guān)閉瀏覽器了后枣宫,你本地的Cookie立刻過期疆柔,你上次的會話已經(jīng)結(jié)束。(事實(shí)上镶柱,關(guān)閉瀏覽器不能結(jié)束一個會話旷档,但大多數(shù)人都會錯誤的認(rèn)為關(guān)閉瀏覽器就等于退出登錄/結(jié)束會話了......)
- 3.上圖中所謂的攻擊網(wǎng)站,可能是一個存在其他漏洞的可信任的經(jīng)常被人訪問的網(wǎng)站歇拆。
常見的CSRF攻擊類型
GET類型的CSRF
GET
類型的CSRF
利用非常簡單鞋屈,只需要一個HTTP
請求
一般會這樣利用:
<img src="http://bank.example/withdraw?amount=10000&for=hacker" >
在受害者訪問含有這個img的頁面后范咨,瀏覽器會自動向http://bank.example/withdraw?account=xiaoming&amount=10000&for=hacker
發(fā)出一次HTTP請求。bank.example就會收到包含受害者登錄信息的一次跨域請求厂庇。
POST類型的CSRF
這種類型的CSRF利用起來通常使用的是一個自動提交的表單渠啊,如:
<form action="http://bank.example/withdraw" method=POST>
<input type="hidden" name="account" value="xiaoming" />
<input type="hidden" name="amount" value="10000" />
<input type="hidden" name="for" value="hacker" />
</form>
<script>
document.forms[0].submit();
</script>
- 訪問該頁面后,表單會自動提交权旷,相當(dāng)于模擬用戶完成了一次POST操作替蛉。
- POST類型的攻擊通常比GET要求更加嚴(yán)格一點(diǎn),但仍并不復(fù)雜拄氯。任何個人網(wǎng)站躲查、博客,被黑客上傳頁面的網(wǎng)站都有可能是發(fā)起攻擊的來源译柏,后端接口不能將安全寄托在僅允許POST上面镣煮。
鏈接類型的CSRF
鏈接類型的
CSRF
并不常見,比起其他兩種用戶打開頁面就中招的情況鄙麦,這種需要用戶點(diǎn)擊鏈接才會觸發(fā)典唇。這種類型通常是在論壇中發(fā)布的圖片中嵌入惡意鏈接,或者以廣告的形式誘導(dǎo)用戶中招胯府,攻擊者通常會以比較夸張的詞語誘騙用戶點(diǎn)擊
例如:
<a taget="_blank">
重磅消息=橄巍!
<a/>
CSRF的特點(diǎn)
- 攻擊一般發(fā)起在第三方網(wǎng)站骂因,而不是被攻擊的網(wǎng)站炎咖。被攻擊的網(wǎng)站無法防止攻擊發(fā)生。
- 攻擊利用受害者在被攻擊網(wǎng)站的登錄憑證侣签,冒充受害者提交操作塘装;而不是直接竊取數(shù)據(jù)。
- 整個過程攻擊者并不能獲取到受害者的登錄憑證影所,僅僅是“冒用”蹦肴。
- 跨站請求可以用各種方式:圖片
URL
、超鏈接猴娩、CORS
阴幌、Form
提交等等。部分請求方式可以直接嵌入在第三方論壇卷中、文章中矛双,難以進(jìn)行追蹤。
CSRF通常是跨域的蟆豫,因?yàn)橥庥蛲ǔ8菀妆还粽哒瓶匾楹觥5侨绻居蛳掠腥菀妆焕玫墓δ埽热缈梢园l(fā)圖和鏈接的論壇和評論區(qū)十减,攻擊可以直接在本域下進(jìn)行栈幸,而且這種攻擊更加危險愤估。
CSRF與 XSS 區(qū)別
- 通常來說
CSRF
是由XSS
實(shí)現(xiàn)的,CSRF
時常也被稱為XSRF
(CSRF 實(shí)現(xiàn)的方式還可以是直接通過命令行發(fā)起請求等)速址。 - 本質(zhì)上講玩焰,
XSS
是代碼注入問題,CSRF
是HTTP
問題芍锚。XSS
是內(nèi)容沒有過濾導(dǎo)致瀏覽器將攻擊者的輸入當(dāng)代碼執(zhí)行昔园。CSRF
則是因?yàn)闉g覽器在發(fā)送HTTP
請求時候自動帶上cookie
,而一般網(wǎng)站的session
都存在cookie
里面(Token
驗(yàn)證可以避免)并炮。
防御
驗(yàn)證碼默刚;強(qiáng)制用戶必須與應(yīng)用進(jìn)行交互,才能完成最終請求渣触。此種方式能很好的遏制
csrf
羡棵,但是用戶體驗(yàn)比較差壹若。Referer check嗅钻;請求來源限制,此種方法成本最低店展,但是并不能保證 100% 有效养篓,因?yàn)榉?wù)器并不是什么時候都能取到
Referer
,而且低版本的瀏覽器存在偽造Referer
的風(fēng)險赂蕴。token柳弄;
token
驗(yàn)證的CSRF
防御機(jī)制是公認(rèn)最合適的方案。(具體可以查看本系列前端鑒權(quán)中對token有詳細(xì)描述)若網(wǎng)站同時存在XSS
漏洞的時候概说,這個方法也是空談碧注。