XSS
XSS:跨站腳本(Cross-site scripting)
XSS:腳本中的不速之客
XSS 全稱“跨站腳本”,是注入攻擊的一種。其特點(diǎn)是不對服務(wù)器端造成任何傷害,而是通過一些正常的站內(nèi)交互途徑,例如發(fā)布評論,提交含有 JavaScript 的內(nèi)容文本。這時服務(wù)器端如果沒有過濾或轉(zhuǎn)義掉這些腳本,作為內(nèi)容發(fā)布到了頁面上,其他用戶訪問這個頁面的時候就會運(yùn)行這些腳本。
運(yùn)行預(yù)期之外的腳本帶來的后果有很多中,可能只是簡單的惡作劇——一個關(guān)不掉的窗口:
while (true) {
alert("你關(guān)不掉我~");
}
CSRF
CSRF:跨站請求偽造(Cross-site request forgery)
CSRF:冒充用戶之手
跟XSS攻擊一樣,存在巨大的危害性,你可以這樣來理解:
攻擊者盜用了你的身份,以你的名義發(fā)送惡意請求,對服務(wù)器來說這個請求是完全合法的,但是卻完成了攻擊者所期望的一個操作,比如以你的名義發(fā)送郵件、發(fā)消息,盜取你的賬號,添加系統(tǒng)管理員,甚至于購買商品、虛擬貨幣轉(zhuǎn)賬等。 如下:其中Web A為存在CSRF漏洞的網(wǎng)站,Web B為攻擊者構(gòu)建的惡意網(wǎng)站,User C為Web A網(wǎng)站的合法用戶。
CSRF攻擊攻擊原理及過程如下:

- 用戶C打開瀏覽器,訪問受信任網(wǎng)站A,輸入用戶名和密碼請求登錄網(wǎng)站A;
- 在用戶信息通過驗(yàn)證后,網(wǎng)站A產(chǎn)生
Cookie信息并返回給瀏覽器,此時用戶登錄網(wǎng)站A成功,可以正常發(fā)送請求到網(wǎng)站A; - 用戶未退出網(wǎng)站A之前,在同一瀏覽器中,打開一個
TAB頁訪問網(wǎng)站B; - 網(wǎng)站B接收到用戶請求后,返回一些攻擊性代碼,并發(fā)出一個請求要求訪問第三方站點(diǎn)A;
- 瀏覽器在接收到這些攻擊性代碼后,根據(jù)網(wǎng)站B的請求,在用戶不知情的情況下攜帶
Cookie信息,向網(wǎng)站A發(fā)出請求。網(wǎng)站A并不知道該請求其實(shí)是由B發(fā)起的,所以會根據(jù)用戶C的Cookie信息以C的權(quán)限處理該請求,導(dǎo)致來自網(wǎng)站B的惡意代碼被執(zhí)行。
防御CSRF攻擊:
目前防御 CSRF 攻擊主要有三種策略:
- 驗(yàn)證
HTTP Referer字段
根據(jù)
HTTP協(xié)議,在HTTP頭中有一個字段叫Referer,它記錄了該HTTP請求的來源地址。在通常情況下,訪問一個安全受限頁面的請求來自于同一個網(wǎng)站,比如需要訪問http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory,用戶必須先登陸bank.example,然后通過點(diǎn)擊頁面上的按鈕來觸發(fā)轉(zhuǎn)賬事件。這時,該轉(zhuǎn)帳請求的Referer值就會是轉(zhuǎn)賬按鈕所在的頁面的 URL,通常是以bank.example域名開頭的地址。而如果黑客要對銀行網(wǎng)站實(shí)施CSRF攻擊,他只能在他自己的網(wǎng)站構(gòu)造請求,當(dāng)用戶通過黑客的網(wǎng)站發(fā)送請求到銀行時,該請求的Referer是指向黑客自己的網(wǎng)站。因此,要防御CSRF攻擊,銀行網(wǎng)站只需要對于每一個轉(zhuǎn)賬請求驗(yàn)證其Referer值,如果是以bank.example開頭的域名,則說明該請求是來自銀行網(wǎng)站自己的請求,是合法的。如果Referer是其他網(wǎng)站的話,則有可能是黑客的CSRF攻擊,拒絕該請求。
這種方法的顯而易見的好處就是簡單易行,網(wǎng)站的普通開發(fā)人員不需要操心CSRF的漏洞,只需要在最后給所有安全敏感的請求統(tǒng)一增加一個攔截器來檢查Referer的值就可以。特別是對于當(dāng)前現(xiàn)有的系統(tǒng),不需要改變當(dāng)前系統(tǒng)的任何已有代碼和邏輯,沒有風(fēng)險,非常便捷。
然而,這種方法并非萬無一失。Referer的值是由瀏覽器提供的,雖然HTTP協(xié)議上有明確的要求,但是每個瀏覽器對于Referer的具體實(shí)現(xiàn)可能有差別,并不能保證瀏覽器自身沒有安全漏洞。使用驗(yàn)證Referer值的方法,就是把安全性都依賴于第三方(即瀏覽器)來保障,從理論上來講,這樣并不安全。事實(shí)上,對于某些瀏覽器,比如IE6或FF2,目前已經(jīng)有一些方法可以篡改Referer值。如果bank.example網(wǎng)站支持IE6瀏覽器,黑客完全可以把用戶瀏覽器的Referer值設(shè)為以bank.example域名開頭的地址,這樣就可以通過驗(yàn)證,從而進(jìn)行CSRF攻擊。
即便是使用最新的瀏覽器,黑客無法篡改Referer值,這種方法仍然有問題。因?yàn)?code>Referer值會記錄下用戶的訪問來源,有些用戶認(rèn)為這樣會侵犯到他們自己的隱私權(quán),特別是有些組織擔(dān)心Referer值會把組織內(nèi)網(wǎng)中的某些信息泄露到外網(wǎng)中。因此,用戶自己可以設(shè)置瀏覽器使其在發(fā)送請求時不再提供Referer。當(dāng)他們正常訪問銀行網(wǎng)站時,網(wǎng)站會因?yàn)檎埱鬀]有Referer值而認(rèn)為是CSRF攻擊,拒絕合法用戶的訪問。
- 在請求地址中添加
token并驗(yàn)證
CSRF攻擊之所以能夠成功,是因?yàn)楹诳涂梢酝耆珎卧煊脩舻恼埱螅撜埱笾兴械挠脩趄?yàn)證信息都是存在于cookie中,因此黑客可以在不知道這些驗(yàn)證信息的情況下直接利用用戶自己的cookie來通過安全驗(yàn)證。要抵御CSRF,關(guān)鍵在于在請求中放入黑客所不能偽造的信息,并且該信息不存在于cookie之中??梢栽?HTTP請求中以參數(shù)的形式加入一個隨機(jī)產(chǎn)生的token,并在服務(wù)器端建立一個攔截器來驗(yàn)證這個token,如果請求中沒有token或者token內(nèi)容不正確,則認(rèn)為可能是CSRF攻擊而拒絕該請求。
這種方法要比檢查Referer要安全一些,token可以在用戶登陸后產(chǎn)生并放于session之中,然后在每次請求時把token從session中拿出,與請求中的token進(jìn)行比對,但這種方法的難點(diǎn)在于如何把 token 以參數(shù)的形式加入請求。對于GET請求,token將附在請求地址之后,這樣 URL 就變成http://url?csrftoken=tokenvalue。 而對于POST請求來說,要在 form 的最后加上<input type=”hidden” name=”csrftoken” value=”tokenvalue”/>,這樣就把 token 以參數(shù)的形式加入請求了。但是,在一個網(wǎng)站中,可以接受請求的地方非常多,要對于每一個請求都加上token是很麻煩的,并且很容易漏掉,通常使用的方法就是在每次頁面加載時,使用javascript遍歷整個dom樹,對于dom中所有的 a 和form標(biāo)簽后加入token。這樣可以解決大部分的請求,但是對于在頁面加載之后動態(tài)生成的html代碼,這種方法就沒有作用,還需要程序員在編碼時手動添加token。
該方法還有一個缺點(diǎn)是難以保證token本身的安全。特別是在一些論壇之類支持用戶自己發(fā)表內(nèi)容的網(wǎng)站,黑客可以在上面發(fā)布自己個人網(wǎng)站的地址。由于系統(tǒng)也會在這個地址后面加上token,黑客可以在自己的網(wǎng)站上得到這個token,并馬上就可以發(fā)動CSRF攻擊。為了避免這一點(diǎn),系統(tǒng)可以在添加token的時候增加一個判斷,如果這個鏈接是鏈到自己本站的,就在后面添加token,如果是通向外網(wǎng)則不加。不過,即使這個csrftoken的形式附加在請求之中,黑客的網(wǎng)站也同樣可以通過Referer來得到這個token值以發(fā)動CSRF攻擊。這也是一些用戶喜歡手動關(guān)閉瀏覽器Referer功能的原因。
- 在 HTTP 頭中自定義屬性并驗(yàn)證
這種方法也是使用 token 并進(jìn)行驗(yàn)證,和上一種方法不同的是,這里并不是把 token 以參數(shù)的形式置于 HTTP 請求之中,而是把它放到 HTTP 頭中自定義的屬性里。通過
XMLHttpRequest這個類,可以一次性給所有該類請求加上csrftoken這個 HTTP 頭屬性,并把 token 值放入其中。這樣解決了上種方法在請求中加入 token 的不便,同時,通過XMLHttpRequest請求的地址不會被記錄到瀏覽器的地址欄,也不用擔(dān)心token會透過Referer泄露到其他網(wǎng)站中去。
然而這種方法的局限性非常大。XMLHttpRequest請求通常用于Ajax方法中對于頁面局部的異步刷新,并非所有的請求都適合用這個類來發(fā)起,而且通過該類請求得到的頁面不能被瀏覽器所記錄下,從而進(jìn)行前進(jìn),后退,刷新,收藏等操作,給用戶帶來不便。另外,對于沒有進(jìn)行CSRF防護(hù)的遺留系統(tǒng)來說,要采用這種方法來進(jìn)行防護(hù),要把所有請求都改為XMLHttpRequest請求,這樣幾乎是要重寫整個網(wǎng)站,這代價無疑是不能接受的