django:CSRF

CSRF

跨站請求偽造(CSRF)與跨站請求腳本正好相反寥粹。跨站請求腳本的問題在于埃元,客戶端信任服務(wù)器端發(fā)送的數(shù)據(jù)涝涤。跨站請求偽造的問題在于岛杀,服務(wù)器信任來自客戶端的數(shù)據(jù)阔拳。

無CSRF時存在的隱患

跨站請求偽造是指攻擊者通過HTTP請求江數(shù)據(jù)傳送到服務(wù)器,從而盜取回話的cookie类嗤。盜取回話cookie之后糊肠,攻擊者不僅可以獲取用戶的信息,還可以修改該cookie關(guān)聯(lián)的賬戶信息遗锣。

CSRF在Django中應(yīng)用

django為用戶實現(xiàn)防止跨站請求偽造的功能货裹,通過中間件django.middleware.csrf.CsrfViewMiddleware 來完成。使用前需要在配置文件 settings.py 中開啟黄伊。而對于django中設(shè)置防跨站請求偽造功能有分為全局和局部。

全局:
中間件 django.middleware.csrf.CsrfViewMiddleware 
局部:
@csrf_protect派殷,為當前函數(shù)強制設(shè)置防跨站請求偽造功能还最,即便settings中沒有設(shè)置全局中間件。
@csrf_exempt毡惜,取消當前函數(shù)防跨站請求偽造功能拓轻,即便settings中設(shè)置了全局中間件。
注意:from django.views.decorators.csrf import csrf_exempt,csrf_protect
  • 處理csrf四種方法
    django 第一次響應(yīng)來自某個客戶端的請求時(get方式)经伙,會在服務(wù)器端隨機生成一個 token扶叉,然后把這個 token 寫在用戶請求的 cookie 里勿锅,同時也會給客戶端頁面發(fā)送一個隨機的 token (form表單中以{% csrf_token %}方式獲取)用以認證。之后客戶端每次以 POST 方式向服務(wù)端提交請求時枣氧,都會帶上這個 token溢十,這樣就能避免被 CSRF 攻擊。

方式:
1达吞、在返回的 HTTP 響應(yīng)的 cookie 里张弛,django 會為你添加一個 csrftoken 字段,其值為一個自動生成的 token酪劫;
2吞鸭、在所有的 POST 表單中,必須包含一個 csrfmiddlewaretoken 字段覆糟;
3刻剥、在處理 POST 請求之前,django 會驗證這個請求的 cookie 里的 csrftoken 字段的值和提交的表單里的 csrfmiddlewaretoken 字段的值是否一樣滩字。如果一樣造虏,則表明這是一個合法的請求;否則踢械,這個請求可能是來自于別人的 csrf 攻擊酗电,返回 403 Forbidden。
4内列、在所有 ajax POST 請求里撵术,添加一個 X-CSRFTOKEN header,其值為 cookie 里的 csrftoken 的值话瞧。

  • Form提交(CSRF)
    那么在Django中CSRF驗證大體是一個什么樣的原理呢嫩与?下面通過一個小例子來簡單說明一下:

1、先在settings.py配置文件中開啟中間件:

MIDDLEWARE = [ 'django.middleware.csrf.CsrfViewMiddleware', ]

2交排、在app01的views.py中寫一個簡單的后臺:

def csrf1(request):
    if request.method == 'GET':
        return render(request, 'csrf1.html')
    elif request.method == 'POST':
        return HttpResponse('CSRF 驗證通過划滋!')

3、在 csrf1.html 模板中寫入:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>CSRF</title>
</head>
<body>
    <form method="POST" action="/csrf1.html">
        <input type="text" name="test" />
        <input type="submit" value="提交"/>
    </form>
</body>
</html>

4埃篓、啟動Django服務(wù)后处坪,進入頁面顯示內(nèi)容:


圖片.png

那么如果這個時候,我們點擊登陸提交架专,django會因為無法通過csrf驗證返回一個403:
5同窘、而csrf驗證其實是對http請求中一段隨機字符串的驗證,那么這段隨機字符串從何而來呢部脚?這個時候我們嘗試把csrf1.html做一個修改添加一句

{% csrf_token %}:

直接在form表單中添加:

{% csrf_token %} -----> 轉(zhuǎn)換成一個hidden屬性的input標簽
{{ csrf_token }} -----> 直接獲取csrf的隨機字符串
注意:本地的cookies中也會添加隨機字符串 ---> 注意key名
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>CSRF</title>
</head>
<body>
    <form method="POST" action="/csrf1.html">
        {% csrf_token %}
        <input type="text" name="test" />
        <input type="submit" value="提交"/>
    </form>
</body>
</html>

6想邦、添加 {%csrf_token%} 之后,我們再通過瀏覽器元素審查委刘,就會發(fā)現(xiàn)一段新的代碼:


圖片.png

并且 cookies 中也攜帶了 csrf_token 隨機碼數(shù)據(jù):


圖片.png

Django在html中創(chuàng)建一個基于input框value值的隨機字符串 丧没,當再次提交數(shù)據(jù)時鹰椒,就會通過 csrf 驗證機制:
CSRF驗證通過!

這就是csrf的基本原理呕童,如果沒有這樣一段隨機字符串做驗證漆际,我們只要在另一個站點,寫一個表單拉庵,提交到這個地址下灿椅,是一樣可以發(fā)送數(shù)據(jù)的,這樣就造成了極大的安全隱患钞支。而我們新添加的csrf_token就是在我們自己的站點中茫蛹,設(shè)置的隱藏參數(shù),用來進行csrf驗證烁挟。

全站禁用

整個框架不使用csrf安全機制婴洼,直接在settings.py文件中注銷,整個網(wǎng)站都不再應(yīng)用撼嗓。

'django.middleware.csrf.CsrfViewMiddleware',

局部禁用:全局使用柬采,但是某些函數(shù)不需要應(yīng)用

settings.py文件中不注銷:

MIDDLEWARE = [ 'django.middleware.csrf.CsrfViewMiddleware', ]

在項目的views.py函數(shù)中導(dǎo)入模塊,給函數(shù)或是類加上對應(yīng)方法的裝飾器:

from django.views.decorators.csrf import csrf_exempt,csrf_protect

@csrf_exempt   #不再做檢測且警!其他沒加裝飾器的函數(shù)還是會檢測
def csrf1(request):
    if request.method == 'GET':
        return render(request,'csrf1.html')
    elif request.method == 'POST':
        return HttpResponse('CSRF 驗證通過粉捻!')
局部使用:全局不使用,但是某些函數(shù)需要應(yīng)用

settings.py文件中注銷:

MIDDLEWARE = [ # 'django.middleware.csrf.CsrfViewMiddleware', ]

from django.views.decorators.csrf import csrf_exempt,csrf_protect

@csrf_protect     #全站不用斑芜,某個函數(shù)需要使用認證
def csrf1(request):
    if request.method == 'GET':
        return render(request,'csrf1.html')
    elif request.method == 'POST':
        return HttpResponse('CSRF 驗證通過肩刃!')
特殊CBV:在CBV應(yīng)用中

django 不認給類內(nèi)的函數(shù)名上添加裝飾器,只能是在類上添加杏头。
同時django限制若是應(yīng)用裝飾器盈包,必須用它的方法去添加,同時添加的語法格式也有限制醇王。

from django.views import View
from django.utils.decorators import method_decorator  #必須使用這個方法
"""
語法:@method_decorator(裝飾器函數(shù)名稱或方法,name='被裝飾的函數(shù)名')
#先導(dǎo)入方法呢燥,然后裝飾器以參數(shù)的形式添加,其次指定要添加這個方法的函數(shù)名<樣式:name="函數(shù)名">
"""
@method_decorator(csrf_protect,name='dispatch')
class Foo(View):
        """請求來了,都是先執(zhí)行類View的內(nèi)置函數(shù)dispatch寓娩,然后再映射到對應(yīng)的方法上叛氨!
    所以給dispatch添加上就相當于給所有的方法添加了"""
    def get(self,request):
        pass
    def post(self,request):
        pass
''' CBV中應(yīng)用裝飾器 '''
#自定義的裝飾器
def wrapper(func):
    def inner(*args,**kwargs):
        return func(*args,**kwargs)
    return inner
# 1. 指定方法上添加裝飾器
class Foo(View):
    @method_decorator(wrapper)    #先導(dǎo)入方法,然后裝飾器以參數(shù)的形式添加
    def get(self,request):
        pass
    def post(self,request):
        pass

# 2. 在類上添加
@method_decorator(wrapper,name='get') # name=方法名棘伴,寫那個方法就是給誰加
@method_decorator(wrapper,name='post') # name=方法名寞埠,寫那個方法就是給誰加
class Foo(View):
    def get(self,request):
        pass
    def post(self,request):
        pass
Ajax 中POST方式提交時候,放置在data中攜帶CSRF
<form method="POST" action="/csrf1.html">
    {% csrf_token %}
    <input id="user" type="text" name="user" />
    <input type="submit" value="提交"/>
    <a onclick="submitForm();">Ajax提交</a>
</form>

<script src="/static/jquery-1.12.4.js"></script>
<script>
    function submitForm(){
        var csrf = $('input[name="csrfmiddlewaretoken"]').val();
        var user = $('#user').val();
        $.ajax({
            url: '/csrf1.html',
            type: 'POST',
            data: { "user":user,'csrfmiddlewaretoken': csrf}, 
            """注意csrf隨機字符串排嫌,后臺有固定的名字接收,這種方式是通過標簽獲取的對應(yīng)值"""
            success:function(arg){
                console.log(arg);   }
        })
    }
 </script>
AJAX 中POST方式提交畸裳,信息放在請求頭中缰犁,從cookies中獲取的csrf隨機字符串

jquery.cookie.js官網(wǎng)下載地址:https://plugins.jquery.com/cookie/
其它下載方式:https://www.jq22.com/jquery-info122

<form method="POST" action="/csrf1.html">
    {% csrf_token %}
    <input id="user" type="text" name="user" />
    <input type="submit" value="提交"/>
    <a onclick="submitForm();">Ajax提交</a>
</form>

<script src="/static/jquery-1.12.4.js"></script>
<script src="/static/jquery.cookie.js"></script>  <!--# 插件:幫助我們自動分割cookie-->
<script>
    function submitForm(){
        var token = $.cookie('csrftoken');  # 獲取cookie值
        var user = $('#user').val();
        $.ajax({
            url: '/csrf1.html',
            type: 'POST',
            headers:{'X-CSRFToken': token},  #注意: X-CSRFToken 是Django規(guī)定寫法
            data: { "user":user},
            success:function(arg){
                console.log(arg);   }
        })
    }
</script>
django csrf 注意事項

注意:ajax POST提交的時候淳地,csrf-token 隨機字符串直接放在data數(shù)據(jù)中的方式為:data:{csrfmiddlewaretoken:"{{ csrf_token }}"}怖糊;

若是導(dǎo)入自己寫的JS文件,那上述方法就不能獲取到Django后臺發(fā)送的隨機字符串颇象,而是需要利用上面介紹的兩種方式獲取(頁面寫上{% csrf_token %}伍伤,通過隱藏的input標簽取value值寫在 POST 提交的data數(shù)據(jù)中;或是從cookie中獲取遣钳,寫在頭文件中扰魂。)

使用django框架時:
  • 每次初始化一個項目時都要看看 django.middleware.csrf.CsrfViewMiddleware 這個中間件;
  • 每次在模板里寫 form 時都需要加一個 {% csrf_token %} tag 蕴茴;
  • 每次發(fā) ajax POST 請求劝评,都需要加一個 X_CSRFTOKEN 的 head ;
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末倦淀,一起剝皮案震驚了整個濱河市蒋畜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌撞叽,老刑警劉巖姻成,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異愿棋,居然都是意外死亡科展,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門糠雨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來才睹,“玉大人,你說我怎么就攤上這事见秤∩笆” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵鹃答,是天一觀的道長乎澄。 經(jīng)常有香客問我,道長测摔,這世上最難降的妖魔是什么置济? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮锋八,結(jié)果婚禮上浙于,老公的妹妹穿的比我還像新娘。我一直安慰自己挟纱,他們只是感情好羞酗,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著紊服,像睡著了一般檀轨。 火紅的嫁衣襯著肌膚如雪胸竞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天参萄,我揣著相機與錄音卫枝,去河邊找鬼。 笑死讹挎,一個胖子當著我的面吹牛校赤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播筒溃,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼马篮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了怜奖?” 一聲冷哼從身側(cè)響起积蔚,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎烦周,沒想到半個月后尽爆,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了易迹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡幅狮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出株灸,到底是詐尸還是另有隱情崇摄,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布慌烧,位于F島的核電站逐抑,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏屹蚊。R本人自食惡果不足惜厕氨,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望汹粤。 院中可真熱鬧命斧,春花似錦、人聲如沸嘱兼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至汇四,卻和暖如春泞莉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背船殉。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留斯嚎,地道東北人利虫。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像堡僻,于是被迫代替她去往敵國和親糠惫。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容