XSS
XSS:跨站腳本(Cross-site scripting)
XSS:腳本中的不速之客
XSS 全稱“跨站腳本”,是注入攻擊的一種。其特點是不對服務(wù)器端造成任何傷害,而是通過一些正常的站內(nèi)交互途徑,例如發(fā)布評論,提交含有 JavaScript 的內(nèi)容文本。這時服務(wù)器端如果沒有過濾或轉(zhuǎn)義掉這些腳本,作為內(nèi)容發(fā)布到了頁面上,其他用戶訪問這個頁面的時候就會運行這些腳本。
運行預(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;
- 在用戶信息通過驗證后,網(wǎng)站A產(chǎn)生
Cookie
信息并返回給瀏覽器,此時用戶登錄網(wǎng)站A成功,可以正常發(fā)送請求到網(wǎng)站A; - 用戶未退出網(wǎng)站A之前,在同一瀏覽器中,打開一個
TAB
頁訪問網(wǎng)站B; - 網(wǎng)站B接收到用戶請求后,返回一些攻擊性代碼,并發(fā)出一個請求要求訪問第三方站點A;
- 瀏覽器在接收到這些攻擊性代碼后,根據(jù)網(wǎng)站B的請求,在用戶不知情的情況下攜帶
Cookie
信息,向網(wǎng)站A發(fā)出請求。網(wǎng)站A并不知道該請求其實是由B發(fā)起的,所以會根據(jù)用戶C的Cookie
信息以C的權(quán)限處理該請求,導(dǎo)致來自網(wǎng)站B的惡意代碼被執(zhí)行。
防御CSRF攻擊:
目前防御 CSRF
攻擊主要有三種策略:
- 驗證
HTTP Referer
字段
根據(jù)
HTTP
協(xié)議,在HTTP
頭中有一個字段叫Referer
,它記錄了該HTTP
請求的來源地址。在通常情況下,訪問一個安全受限頁面的請求來自于同一個網(wǎng)站,比如需要訪問http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory
,用戶必須先登陸bank.example
,然后通過點擊頁面上的按鈕來觸發(fā)轉(zhuǎn)賬事件。這時,該轉(zhuǎn)帳請求的Referer
值就會是轉(zhuǎn)賬按鈕所在的頁面的 URL,通常是以bank.example
域名開頭的地址。而如果黑客要對銀行網(wǎng)站實施CSRF
攻擊,他只能在他自己的網(wǎng)站構(gòu)造請求,當(dāng)用戶通過黑客的網(wǎng)站發(fā)送請求到銀行時,該請求的Referer
是指向黑客自己的網(wǎng)站。因此,要防御CSRF
攻擊,銀行網(wǎng)站只需要對于每一個轉(zhuǎ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
的具體實現(xiàn)可能有差別,并不能保證瀏覽器自身沒有安全漏洞。使用驗證Referer
值的方法,就是把安全性都依賴于第三方(即瀏覽器)來保障,從理論上來講,這樣并不安全。事實上,對于某些瀏覽器,比如IE6
或FF2
,目前已經(jīng)有一些方法可以篡改Referer
值。如果bank.example
網(wǎng)站支持IE6
瀏覽器,黑客完全可以把用戶瀏覽器的Referer
值設(shè)為以bank.example
域名開頭的地址,這樣就可以通過驗證,從而進(jìn)行CSRF
攻擊。
即便是使用最新的瀏覽器,黑客無法篡改Referer
值,這種方法仍然有問題。因為Referer
值會記錄下用戶的訪問來源,有些用戶認(rèn)為這樣會侵犯到他們自己的隱私權(quán),特別是有些組織擔(dān)心Referer
值會把組織內(nèi)網(wǎng)中的某些信息泄露到外網(wǎng)中。因此,用戶自己可以設(shè)置瀏覽器使其在發(fā)送請求時不再提供Referer
。當(dāng)他們正常訪問銀行網(wǎng)站時,網(wǎng)站會因為請求沒有Referer
值而認(rèn)為是CSRF
攻擊,拒絕合法用戶的訪問。
- 在請求地址中添加
token
并驗證
CSRF
攻擊之所以能夠成功,是因為黑客可以完全偽造用戶的請求,該請求中所有的用戶驗證信息都是存在于cookie
中,因此黑客可以在不知道這些驗證信息的情況下直接利用用戶自己的cookie
來通過安全驗證。要抵御CSRF
,關(guān)鍵在于在請求中放入黑客所不能偽造的信息,并且該信息不存在于cookie
之中。可以在HTTP
請求中以參數(shù)的形式加入一個隨機(jī)產(chǎn)生的token
,并在服務(wù)器端建立一個攔截器來驗證這個token
,如果請求中沒有token
或者token
內(nèi)容不正確,則認(rèn)為可能是CSRF
攻擊而拒絕該請求。
這種方法要比檢查Referer
要安全一些,token
可以在用戶登陸后產(chǎn)生并放于session
之中,然后在每次請求時把token
從session
中拿出,與請求中的token
進(jì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
。
該方法還有一個缺點是難以保證token
本身的安全。特別是在一些論壇之類支持用戶自己發(fā)表內(nèi)容的網(wǎng)站,黑客可以在上面發(fā)布自己個人網(wǎng)站的地址。由于系統(tǒng)也會在這個地址后面加上token
,黑客可以在自己的網(wǎng)站上得到這個token
,并馬上就可以發(fā)動CSRF
攻擊。為了避免這一點,系統(tǒng)可以在添加token
的時候增加一個判斷,如果這個鏈接是鏈到自己本站的,就在后面添加token
,如果是通向外網(wǎng)則不加。不過,即使這個csrftoken
的形式附加在請求之中,黑客的網(wǎng)站也同樣可以通過Referer
來得到這個token
值以發(fā)動CSRF
攻擊。這也是一些用戶喜歡手動關(guān)閉瀏覽器Referer
功能的原因。
- 在 HTTP 頭中自定義屬性并驗證
這種方法也是使用 token 并進(jì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)站,這代價無疑是不能接受的