1. CSRF
- CSRF: Cross-site request forgery, 跨站請(qǐng)求偽造,也被稱為one-click attack或者session riding, 通陈沸牵縮寫為CSRF或者XSRF烛愧。
- 是一種挾持用戶在當(dāng)前已登陸的web應(yīng)用程序上執(zhí)行非本意的操作的攻擊方法。
- 跟跨網(wǎng)頁腳本(XSS)相比郎仆,XSS利用的是用戶對(duì)特定網(wǎng)站的信任,CSRF利用的是網(wǎng)站對(duì)用戶網(wǎng)頁瀏覽器的信任。
Cross-site request forgery, also known as one-click attack or session riding and abbreviated as CSRF or XSRF, is a type of malicious exploit of a website where unauthorized commands are transmitted from a user that the web application trusts. There are many ways in which a malicious website can transmit such commands; specially-crafted image tags, hidden forms, and JavaScript XMLHttpRequests, for example, can all work without the user's interaction or even knowledge. Unlike cross-site scripting(XSS), which exploits the trust a user has for a particular site, CSRF exploits the trust that a site has in a user's browser.
2. 攻擊的細(xì)節(jié)
- 跨站請(qǐng)求攻擊裸影,簡單地說,就是攻擊者通過一些技術(shù)手段欺騙用戶的瀏覽器去訪問一個(gè)自己曾經(jīng)認(rèn)證過的網(wǎng)站并執(zhí)行一些操作(如發(fā)郵件军熏,發(fā)消息轩猩,甚至財(cái)產(chǎn)操作如轉(zhuǎn)賬和購買商品)。由于瀏覽器曾經(jīng)認(rèn)證過荡澎,所以被訪問的網(wǎng)站會(huì)認(rèn)為是真正的用戶操作而去執(zhí)行均践。這里用了web中用戶身份驗(yàn)證的一個(gè)漏洞:簡單的身份驗(yàn)證只能保證請(qǐng)求發(fā)自某個(gè)用戶的瀏覽器,卻不能保證請(qǐng)求本身是用戶自愿發(fā)出的摩幔。
2.1 攻擊過程
- 瀏覽者C登陸信任網(wǎng)站A彤委。
- 驗(yàn)證通過,在用戶C處產(chǎn)生A的cookie并存儲(chǔ)在本地或衡。
- 用戶在沒有登出A網(wǎng)站的情況下焦影,訪問危險(xiǎn)網(wǎng)站B。
- 危險(xiǎn)網(wǎng)站B要求用戶C的瀏覽器訪問第三方站點(diǎn)A封断,發(fā)出一個(gè)請(qǐng)求斯辰。
- 根據(jù)危險(xiǎn)網(wǎng)站B的要求,用戶C的瀏覽器帶著驗(yàn)證通過后產(chǎn)出的Cookie訪問網(wǎng)站A坡疼。
- 網(wǎng)站A不知道這個(gè)請(qǐng)求是用戶C的瀏覽器發(fā)出的椒涯,還是危險(xiǎn)網(wǎng)站B發(fā)出的。因?yàn)闉g覽器會(huì)自動(dòng)帶上用戶C的Cookie,所以網(wǎng)站A會(huì)根據(jù)用戶的權(quán)限處理請(qǐng)求废岂,這樣網(wǎng)站B就達(dá)到了模擬用戶操作的目的祖搓。
3. 防御方法
3.1 檢查Referer字段
- HTTP頭中有一個(gè)Refer字段,這個(gè)字段用以標(biāo)明請(qǐng)求來源于哪個(gè)地址湖苞。在處理敏感數(shù)據(jù)請(qǐng)求時(shí)拯欧,通常來說,Referer字段應(yīng)和請(qǐng)求的地址位于同一域名下财骨。以轉(zhuǎn)賬為例镐作,Referer字段地址通常應(yīng)該是轉(zhuǎn)賬按鈕所在的網(wǎng)頁地址,應(yīng)該也位于www.example.com下隆箩。如果是CSRF攻擊傳來的請(qǐng)求该贾,Referer字段會(huì)是包含惡意網(wǎng)址的地址,不會(huì)位于www.example.com之下捌臊,這時(shí)候服務(wù)器就能識(shí)別出惡意的訪問杨蛋。
3.2 添加校驗(yàn)token
- 由于CSRF的本質(zhì)在于攻擊者欺騙服務(wù)器,使服務(wù)器認(rèn)為請(qǐng)求是經(jīng)過驗(yàn)證的用戶發(fā)送的理澎。所以如果要求在訪問敏感數(shù)據(jù)請(qǐng)求時(shí)逞力,要求用戶瀏覽器提供不保存在cookie中,并且攻擊者無法偽造的數(shù)據(jù)作為校驗(yàn)糠爬,那么攻擊者就無法再執(zhí)行CSRF攻擊寇荧。這種數(shù)據(jù)通常是表單中的一個(gè)數(shù)據(jù)項(xiàng)。服務(wù)器將其生成并附加在表單中执隧,其內(nèi)容是一個(gè)偽亂數(shù)(每次產(chǎn)生的值都不同)揩抡。當(dāng)客戶端通過表單提交請(qǐng)求時(shí),這個(gè)偽亂數(shù)也一并提交上去以供驗(yàn)證镀琉。正常的訪問時(shí)峦嗤,客戶端瀏覽器能夠正確得到并傳回這個(gè)偽亂數(shù),而通過CSRF傳來的欺騙性攻擊中滚粟,攻擊者無從事先得知這個(gè)偽亂數(shù)的值寻仗,服務(wù)器端就會(huì)因?yàn)樾r?yàn)token的值為空或者錯(cuò)誤刃泌,拒絕這個(gè)可疑請(qǐng)求凡壤。
4. django中出現(xiàn)csrf驗(yàn)證失敗解決辦法
4.1 在django 項(xiàng)目的setting中將csrf中間件屏蔽,不推薦耙替!
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
#'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
4.2 在form表單中添加{% csrf_token%}
- 在使用post方法的form中添加{% csrf_token %}
<div class="container">
<div class="login">
<label>用戶登錄</label>
<form method="post" action="/user/login/">
{% csrf_token %}
賬號(hào):<input type="text" maxlength="20" name="username"><br>
密碼:<input type="password" maxlength="20" name="password"><br>
<span style="color: red;">{{ error }}</span>
<input type="submit" value="登錄">
</form>
</div>
</div>
- 在實(shí)際運(yùn)行過程中亚侠,csrf_token被替換成了如下代碼
<div class="container">
<div class="login">
<label>用戶登錄</label>
<form method="post" action="/user/login/">
<input type='hidden' name='csrfmiddlewaretoken' value='HedcdWXjTwCxyVOd4d8MKLmiCTHZpmU0X0nkQ6dzbBcMawOAwkNdDjZtariC2i1B' />
賬號(hào):<input type="text" maxlength="20" name="username"><br>
密碼:<input type="password" maxlength="20" name="password"><br>
<span style="color: red;"></span>
<input type="submit" value="登錄">
</form>
</div>
</div>
- 我使用的django版本是1.11.6。通過使用Fiddler軟件抓包分析俗扇,在通信過程中發(fā)現(xiàn)請(qǐng)求頭中cookie字段有了csrftoken值硝烂。
Request sent 137 bytes of Cookie data:
__lnkrntdmcvrd=-1
csrftoken=Htr860vr38EaEumkfWuvEoW3BmyXInDcXfBgJaLHldepg5mHH39WxWze9U9AljKN
sessionid=qjt57gldisr5gb6x5k663l9tv1axl86f
因此可以得出結(jié)論django中的csrf驗(yàn)證需要form中的隱藏字段和cookie中的csrftoken一同發(fā)給服務(wù)器完成csrf驗(yàn)證。
P.S.
- 前端中沒有絕對(duì)的安全铜幽,前端中瀏覽器和服務(wù)器通信過程中的數(shù)據(jù)都是可以偽造的滞谢。