CSRF定義
CSRF,即(Cross-site request forgery), 中文名為跨站請求偽造。是一種挾持用戶在當前已登錄的Web應(yīng)用程序上執(zhí)行非本意的操作的一種攻擊方式。CSRF攻擊的本質(zhì)在于利用用戶的身份,執(zhí)行非本意的操作。根據(jù)CSRF的全名,可以得出的結(jié)論是:CSRF的請求是跨域且偽造的。
跨域指的是請求來源于其他網(wǎng)站。比如說,目標網(wǎng)站上的刪除文章功能接收到來自其他網(wǎng)站的刪除文章的請求,那么這個請求就是跨域的。
偽造指的是如果這個請求不是用戶自身的意愿,那么這個請求就是偽造的。
簡單的說,跨站請求偽造的攻擊是攻擊者通過一些技術(shù)手段欺騙用戶的瀏覽器去訪問用戶曾經(jīng)認證過的網(wǎng)站并執(zhí)行一些操作(如發(fā)送郵件、發(fā)消息、甚至財產(chǎn)操作如轉(zhuǎn)賬和購買商品等)。由于瀏覽器曾經(jīng)認證過,所以被訪問的網(wǎng)站會認為是真正的用戶操作而去執(zhí)行。這利用了web登錄身份認證的一個漏洞:簡單的身份認證只能保證請求來自用戶的瀏覽器,但不能識別請求是用戶自愿發(fā)出的。
CSRF分類
GET CSRF:
兩個網(wǎng)站的域名不一樣,目標網(wǎng)站A上有一個刪除文章的功能,通常是用戶單擊’刪除文章‘鏈接時才會刪除指定的文章。這個鏈接是www.a.com/blog/del?id=1, id代表不同的文章。實際上就是發(fā)起一個GET請求。
如果在目標網(wǎng)站A上存在XSS漏洞,那么可以利用這個XSS漏洞來進行攻擊。注意,XSS攻擊是在用戶的瀏覽器上進行的。如果對XSS攻擊不熟悉的朋友,可以看看上篇文章。
- 使用Ajax發(fā)起一個GET請求,因為是在目標網(wǎng)站上,所以符合同源策略。請求參數(shù)為id=1, 請求目標地址為www.a.com/blog/del。
- 或者在目標網(wǎng)站A上動態(tài)創(chuàng)建一個標簽(script, img, iframe等),將其src指向www.a.com/blog/del?id=1, 那么攻擊就會發(fā)起。實際上通過這種方式發(fā)起的請求就是一個GET請求。
- 最后欺騙用戶登錄目標網(wǎng)站A,那么攻擊就會發(fā)生。
如果在目標網(wǎng)站A上不存在XSS漏洞,那么可以利用GET CSRF進行攻擊
- 無法使用Ajax發(fā)起GET請求。因為CSRF請求是跨域的,而Ajax有同源策略的限制。
- 可以通過在惡意網(wǎng)站B上靜態(tài)或者動態(tài)創(chuàng)建img,script等標簽發(fā)起GET請求。將其src屬性指向www.a.com/blog/del?id=1。通過標簽的方式發(fā)起的請求不受同源策略的限制。
- 最后欺騙已經(jīng)登錄目標網(wǎng)站A的用戶訪問惡意網(wǎng)站B,那么攻擊就會發(fā)生。此時惡意網(wǎng)站B的請求是身份認證后的。
對比CSRF和XSS攻擊可以看出,CSRF攻擊有以下幾個關(guān)鍵點
- 請求是跨域的。可以看出請求是從惡意網(wǎng)站B上發(fā)出的
- 通過img, script等標簽來發(fā)起一個GET請求。因為這些標簽不受同源策略的限制
- 發(fā)出的請求是身份認證后的。這一點是CSRF中最重要的一點。如以下代碼
惡意網(wǎng)站B發(fā)出的刪除文章的GET請求的請求頭
GET /blog/del?id=1 HTTP/1.1
Host: www.a.com
Referer: http://www.b.com/csrf.html
Connection: Keep-Alive
Cookie: name=kk
Other-Request-Name: Other-Request-Value:
目標網(wǎng)站A發(fā)出的刪除文章的GET請求的請求頭
GET /blog/del?id=1 HTTP/1.1
Host: www.a.com
Referer: http://www.a.com/blog/
Connection: Keep-Alive
Cookie: name=kk
Other-Request-Name: Other-Request-Value:
對比以上的代碼可以看出,只有Referer字段不同。也就是說,只有請求來源不相同,而發(fā)送刪除文章的請求時都會帶上相同的cookie信息。這樣的請求就是身份認證后的,CSRF攻擊就會成功。
POST CSRF:
POST請求實際上就是在惡意網(wǎng)站B上發(fā)起一個POST請求,同樣的,這個請求也是跨域和身份認證后的。如靜態(tài)或動態(tài)的創(chuàng)建一個form表單,當用戶訪問到這個惡意網(wǎng)站B時,就會提交這個表單。
假如目標網(wǎng)站A上有‘寫文章’的功能,那么我們就可以動態(tài)創(chuàng)建form標簽,然后修改文章的題目。
www.b.com/csrf.html
function setForm () {
var form = document.createElement('form')
form.action = 'www.a.com/blog/article'
form.methods = 'POST'
var input = document.createElement('input')
input.type = 'text'
input.value = 'csfr攻擊啦!'
input.id = 'title'
form.appendChild(input)
document.body.appendChild(form)
form.submit()
}
setForm()
上面代碼可以看出,動態(tài)創(chuàng)建了form表單,然后調(diào)用submit方法。就可以通過跨域的偽造請求來實現(xiàn)修改目標網(wǎng)站A的某篇文章的標題了。
以上說了GET和POST的CSRF攻擊。本質(zhì)上都是欺騙用戶以自己的身份去執(zhí)行非本意的操作。欺騙流程大致如下
- 首先欺騙用戶登錄目標網(wǎng)站。
- 然后欺騙用戶登錄惡意網(wǎng)站。這種惡意的網(wǎng)站有很多種形式,藏身于網(wǎng)頁中的許多地方。此外,攻擊者也不需要控制放置惡意網(wǎng)址的網(wǎng)站。例如他可以將這種地址藏在論壇,博客等任何用戶生成內(nèi)容的網(wǎng)站中。這意味著如果服務(wù)器端沒有合適的防御措施的話,用戶即使訪問熟悉的可信網(wǎng)站也有受攻擊的危險。
CSRF危害
- 模擬表單提交盜取用戶資金。實際上就是上面所說的POST CSRF攻擊
- 篡改目標網(wǎng)站上的用戶數(shù)據(jù)。
- 盜取用戶隱私數(shù)據(jù)
CSRF防范
1. 檢測請求頭中的Referer字段
從GET CSRF例子中可以看到,目標網(wǎng)站A和惡意網(wǎng)站B發(fā)出的請求中,請求頭唯一的不同就是Referer字段。通常來說,Referer字段通常與Host字段的域名是一樣的。
以上面刪除文章功能為例,在目標網(wǎng)站A中的Referer字段為http://www.a.com/blog/,而惡意網(wǎng)站B中的Referer字段為http://www.b.com/csrf.html。所以根據(jù)Referer字段與Host字段在同一域名下的規(guī)則,可以檢測Referer字段值,如果發(fā)現(xiàn)其與Host值不在同一域名下,這時候服務(wù)器就能夠識別出惡意的訪問了。
2.添加檢驗token
由于CSRF的本質(zhì)在于攻擊者欺騙用戶去訪問自己設(shè)置的地址,所以如果要求在訪問敏感數(shù)據(jù)請求時,要求用戶瀏覽器提供不保存在cookie中,并且攻擊者無法偽造的數(shù)據(jù)作為校驗,那么攻擊者就無法再執(zhí)行CSRF攻擊。這種數(shù)據(jù)通常是表單中的一個數(shù)據(jù)項。服務(wù)器將其生成并附加在表單中,其內(nèi)容是一個隨機數(shù)。即<input type="hidden" name="_csrf_token" value="xxxx">)的形式。
當客戶端通過表單提交請求時,這個隨機數(shù)也一并提交上去以供校驗。正常的訪問時,客戶端瀏覽器能夠正確得到并傳回這個隨機數(shù),而通過CSRF傳來的欺騙性攻擊中,攻擊者無從事先得知這個隨機數(shù)的值,服務(wù)器端就會因為校驗token的值為空或者錯誤,拒絕這個可疑請求。
為了防范CSRF,在需要增刪改數(shù)據(jù)時,使用POST請求,而不要使用GET請求。
具體的方案如下:
- 服務(wù)端在收到客戶端請求時,生成一個隨機數(shù),在渲染頁面時將隨機數(shù)埋入頁面(一般埋入form表單中),<input type="hidden" name="_csrf_token" value="xxxx">)`的形式。每次刷新頁面后這個隨機數(shù)都會改變,并在服務(wù)器中存儲。
- 服務(wù)端設(shè)置Set-Cookie, 把該隨機數(shù)作為cookie種入用戶瀏覽器。
- 當用戶發(fā)送GET或POST請求時帶上_csrf_token參數(shù)(對于form表單直接提交即可)
- 后臺在接受到請求后解析請求頭中的cookie字段,獲取_csrf_token的值,然后和用戶請求提交的_csrf_token值做比較。如果相等則表示請求來源是合法的。