csrf

csrf: Cross Site Request Forgery, 跨站請求僞造

什麼是 CSRFhtml

  CSRF, Cross Site Request Forgery, 跨站點請求僞造。舉例來說,某個惡意的網站上有一個指向你的網站的連接,若是某個用戶已經登陸到你的網站上了,那麼當這個用戶點擊這個惡意網站上的那個連接時,就會向你的網站發來一個請求,你的網站會覺得這個請求是用戶本身發來的,其實呢,這個請求是那個惡意網站僞造的。
python

 

經典案例:銀行轉帳:jquery

 

 

 

 

 

 

 

 

 

 

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     CSRF 攻擊能夠在受害者絕不知情的狀況下以受害者名義僞造請求發送給受攻擊站點,從而在並未受權的狀況下執行在權限保護之下的操做。
  好比說,受害者 Bob 在銀行有一筆存款,經過對銀行的網站發送請求 http://bank.example/withdraw?account=bob&amount=1000000&for=bob2 可使 Bob 把 1000000 的存款轉到 bob2 的帳號下。一般狀況下,該請求發送到網站後,服務器會先驗證該請求是否來自一個合法的 session,而且該 session 的用戶 Bob 已經成功登錄。黑客 Mallory 本身在該銀行也有帳戶,他知道上文中的 URL 能夠把錢進行轉賬操做。Mallory 能夠本身發送一個請求給銀行:http://bank.example/withdrawaccount=bob&amount=1000000&for=Mallory。可是這個請求來自 Mallory 而非 Bob,他不能經過安全認證,所以該請求不會起做用。這時,Mallory 想到使用 CSRF 的攻擊方式,他先本身作一個網站,在網站中放入以下代碼: src=」http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory 」,而且經過廣告等誘使 Bob 來訪問他的網站。當 Bob 訪問該網站時,上述 url 就會從 Bob 的瀏覽器發向銀行,而這個請求會附帶 Bob 瀏覽器中的 cookie 一塊兒發向銀行服務器。大多數狀況下,該請求會失敗,由於他要求 Bob 的認證信息。可是,若是 Bob 當時恰巧剛訪問他的銀行後不久,他的瀏覽器與銀行網站之間的 session 還沒有過時,瀏覽器的 cookie 之中含有 Bob 的認證信息。這時,悲劇發生了,這個 url 請求就會獲得響應,錢將從 Bob 的帳號轉移到 Mallory 的帳號,而 Bob 當時絕不知情。等之後 Bob 發現帳戶錢少了,即便他去銀行查詢日誌,他也只能發現確實有一個來自於他本人的合法請求轉移了資金,沒有任何被攻擊的痕跡。而 Mallory 則能夠拿到錢後逍遙法外。ajax

Django 提供的 CSRF 防禦機制

  django 第一次響應來自某個客戶端的請求時(get方式),會在服務器端隨機生成一個 token,而後把這個 token 寫在用戶請求的 cookie 裏,同時也會給客戶端頁面發送一個隨機的 token (form表單中以{% csrf_token %}方式獲取)用以認證。以後客戶端每次以 POST 方式向服務端提交請求時,都會帶上這個 token,這樣就能避免被 CSRF 攻擊。django

  1.在返回的 HTTP 響應的 cookie 裏,django 會爲你添加一個 csrftoken 字段,其值爲一個自動生成的 token;
  2.在全部的 POST 表單中,必須包含一個 csrfmiddlewaretoken 字段 (只須要在模板里加一個 tag, django 就會自動幫你生成,見下面)
  3.在處理 POST 請求以前,django 會驗證這個請求的 cookie 裏的 csrftoken 字段的值和提交的表單裏的 csrfmiddlewaretoken 字段的值是否同樣。若是同樣,則代表這是一個合法的請求,不然,這個請求多是來自於別人的 csrf 攻擊,返回 403 Forbidden.
  4.在全部 ajax POST 請求裏,添加一個 X-CSRFTOKEN header,其值爲 cookie 裏的 csrftoken 的值
瀏覽器

Django 裏如何使用 CSRF 防禦

  首先,最基本的原則是:GET 請求不要用!有反作用!也就是說任何處理 GET 請求的代碼對資源的訪問都必定要是「只讀「的;
  其次,要啓用 django.middleware.csrf.CsrfViewMiddleware 這個中間件;
  最後,在全部的 POST 表單元素中,須要加上一個 {% csrf_token %} tag。緣由:用於csrf在模版渲染過程當中,會自動爲表單添加一個名爲 csrfmiddlewaretoken , type屬性爲 hidden 的 input。安全

Django CSRF 應用<基本應用,FBV和CBV不一樣,ajax應用>服務器

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
a. 基本應用:
             直接在form表單中添加:就能應用。
             { % csrf_token % } - - - - - > 轉換成一個hidden屬性的 input 標籤
             {{ csrf_token }} - - - - - > 直接獲取csrf的隨機字符串
             
             注意:本地的cookies中也會添加隨機字符串 - - - > 注意key名
         
     b. 全站禁用:
         - 整個框架不使用csrf安全機制,直接在settings.py文件中註銷,整個網站都再也不應用。
         # 'django.middleware.csrf.CsrfViewMiddleware',
     
     c. 局部禁用:全局使用,可是某些函數不須要應用。
         - settings.py文件中不註銷,在項目的views.py函數中導入模塊,給函數或是類加上對應方法的裝飾器:
         'django.middleware.csrf.CsrfViewMiddleware' ,
         
         from django.views.decorators.csrf import csrf_exempt,csrf_protect
 
         @csrf_exempt   #再也不作檢測!其餘沒加裝飾器的函數仍是會檢測
         def csrf1(request):
 
             if request.method = = 'GET' :
                 return render(request, 'csrf1.html' )
             else :
                 return HttpResponse( 'ok' )
     
     d. 局部使用:全局不使用,可是某些函數須要應用。
         
         # 'django.middleware.csrf.CsrfViewMiddleware',
         
         from django.views.decorators.csrf import csrf_exempt,csrf_protect
 
         @csrf_protect  #全站不用,某個函數須要使用認證的時候
         def csrf1(request):
 
             if request.method = = 'GET' :
                 return render(request, 'csrf1.html' )
             else :
                 return HttpResponse( 'ok' )
         
     e. 特殊CBV:在CBV應用中,有些特殊!
         django 不認給類內的函數名上添加裝飾器,只能是在類上添加。
         同時django限制如果應用裝飾器,必須用它的方法去添加,同時添加的語法格式也有限制。
         
             from django.views import View
             from django.utils.decorators import method_decorator  #必須使用這個方法
                 - 語法:@method_decorator(裝飾器函數名稱或方法,name = '被裝飾的函數名' )
 
             #先導入方法,而後裝飾器以參數的形式添加,其次指定要添加這個方法的函數名<樣式:name="函數名">
                     
             @method_decorator (csrf_protect,name = 'dispatch' )
             class Foo(View):
                 #請求來了,都是先執行類View的內置函數dispatch,而後再映射到對應的方法上!
                 #因此給dispatch添加上就至關於給全部的方法添加了
                 def get( self ,request):
                     pass
 
                 def post( self ,request):
                     pass
         
         PS:CBV中添加裝飾器
             #自定義的裝飾器
             def wrapper(func):
                 def inner( * args, * * kwargs):
                     return func( * args, * * kwargs)
                 return inner
             
             # 1. 指定方法上添加裝飾器
                     class Foo(View):
                         @method_decorator (wrapper)    #先導入方法,而後裝飾器以參數的形式添加
                         def get( self ,request):
                             pass
                                 
                         def post( self ,request):
                             pass
             # 2. 在類上添加
                     @method_decorator (wrapper,name = 'dispatch' )
                     class Foo(View):
                         def get( self ,request):
                             pass
                         def post( self ,request):
                             pass
             
         
     f.Ajax提交數據時候,攜帶CSRF:
         a. 以post方式提交,放置在data中攜帶
         
             <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隨機字符串,後臺有固定的名字接收,這種方式是經過標籤獲取的對應值                                                                    success:function(arg){
                             console.log(arg);
                         }
                     })
                 }
 
             < / script>     b. POST方式提交,信息放在請求頭中,從cookies中獲取的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 src = "/static/jquery.cookie.js" >< / script>
 
                 <script>
                     function submitForm(){
                         var token = $.cookie( 'csrftoken' );
                         var user = $( '#user' ).val();
                         $.ajax({
                             url: '/csrf1.html' ,
                             type : 'POST' ,
                             headers:{ 'X-CSRFToken' : token},  #注意csrf隨機字符串後臺有固定的名字接收
                             data: { "user" :user},
                             success:function(arg){
                                 console.log(arg);
                             }
                         })
                     }
                 < / script>

                                                 

django csrf注意點:

注意必定注意:ajax POST提交的時候,csrf-token 隨機字符串 直接放在data數據中的方式爲:data:{csrfmiddlewaretoken:"{{ csrf_token }}"}cookie

 

  如果導入本身寫的JS文件,那上述方法就不能獲取到Django後臺發送的隨機字符串,而是須要利用上面介紹的兩種方式獲取(頁面寫上{% csrf_token %},經過隱藏的input標籤取value值寫在POST提交的data數據中;或是從cookie中獲取,寫在頭文件中。)session

使用django框架時:   每次初始化一個項目時都要看看 django.middleware.csrf.CsrfViewMiddleware 這個中間件   每次在模板裏寫 form 時都須要加一個 {% csrf_token %} tag   每次發 ajax POST 請求,都須要加一個 X_CSRFTOKEN 的 header 流程:   用戶第一次訪問頁面,確定是get請求,此時服務端就會給客戶端發送一段隨機字符串的數據,當客戶提交數據的時候,常在POST請求中帶回,就會發送隨機字符串給服務端(上一次請求獲取的數據)用於驗證。   服務端給客戶端發送的隨機字符串做爲一種安全機制,客戶端往服務端發送請求時再攜帶回來,用於匹配認證。   能夠從form表單中接收,也能夠在cookies中查看,注意:這兩個的隨機字符串是不一樣的!   若是開啓了csrf認證,後臺沒有拿到對應的字符串的話就會報錯---> 403

相關文章
相關標籤/搜索