Django中與CSRF相關的內容

Django中與CSRF相關的內容

1.什麼是CSRF?

​ CSRF(Cross-site request forgery)跨站請求僞造,也被稱爲「One Click Attack」或者Session Riding,一般縮寫爲CSRF或者XSRF,是一種對網站的惡意利用。儘管聽起來像跨站腳本(XSS),但它與XSS很是不一樣,XSS利用站點內的信任用戶,而CSRF則經過假裝成受信任用戶的請求來利用受信任的網站。與XSS攻擊相比,CSRF攻擊每每不大流行(所以對其進行防範的資源也至關稀少)和難以防範,因此被認爲比XSS更具危險性。html

2.Django下的CSRF認證機制

​ django 第一次響應來自某個客戶端的請求時,會在服務器端隨機生成一個 csrftoken值,把這個 csrftoken 放在 cookie 裏。而後每次請求都帶着這個值過來完成校驗。python

token字符串的前32位是salt, 後面是加密後的token, 經過salt能解密出惟一的secret。官方文檔中說到,檢驗token時,只比較secret是否和cookie中的secret值同樣,jquery

而不是比較整個token。django會驗證表單中的token和cookie中token是否能解出一樣的secret,secret同樣則本次請求合法,這樣就能避免被 CSRF 攻擊。ajax

​ 例如:在html 中, 爲每一個post請求的form 表單增長一個 {% csrf_token %} 標籤,它的功能實際上是給form表單增長一個隱藏的input標籤。服務端收到請求後,django

django 會對這個請求的 cookie 裏的 csrftoken 字段的值和提交的表單裏的 csrfmiddlewaretoken 字段的值進行處理,比較secret是否同樣,secret同樣則本次請求合法。服務器

3.具體的實現方法

django經過中間件 django.middleware.csrf.CsrfViewMiddleware 來防止跨站請求僞造。cookie

#settings.py
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',#csrf的認證
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

3-1 form表單當中附加csrftoken

#爲每一個post請求的form 表單增長一個 {% csrf_token %} 標籤,若是不添加,post請求的時候你會發現一個 Forbidden的錯誤
    
    <form action="" method="post" id="loginForm" novalidate="novalidate">
    
    {% csrf_token %}#
    
    <div>
      <input type="text" name="username" class="username" placeholder="用戶名" autocomplete="off">
    </div>
    <div>
      <input type="password" name="password" class="password" placeholder="密碼" oncontextmenu="return false"
             onpaste="return false">
    </div>
    <button id="submit" type="submit">登 陸</button>
    <span style="color: red;">{{ error }}</span>
  </form>

3-2 Ajax的post請求設置csrf_token的方式

方式1:
經過獲取隱藏的input標籤中的csrfmiddlewaretoken值,放置在data中發送。
    
    data:{
        
        csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val(), #form表單裏必須寫{% csrf_token %}#}

    },
方式2:
data:{
       
        csrfmiddlewaretoken:"{{ csrf_token }}", #form表單裏不用寫{% csrf_token %}  模板語法替換產生

    },
        

#示例:
 <script src="{% static 'jquery.js' %}"></script>
    
    #基於jQuery的實現
    <script>
        $('#btn').click(function () {
            
            $.ajax({ 
                
                url:"{% url 'login' %}", 
                type:'post' ,
                data:{  
                    username:$('[name=username]').val(),
                    password:$('[name=password]').val(),
                    
                    csrfmiddlewaretoken:$('[name=csrfmiddlewaretoken]').val(),#form表單裏必須寫 {% csrf_token %}#}--方式1
                        #或
                    csrfmiddlewaretoken:"{{ csrf_token }}", #form表單裏不用寫 {% csrf_token %}--方式2 
                },

                success:function(res){  
                    var resStr = JOSN.parse(res);
                    console.log(res,typeof res);    
                }
            })
        })
        
    </script>
方式3:經過獲取返回的cookie中的字符串,放置在請求頭中發送。
注意:須要引入一個jquery.cookie.js插件,jquery操做cookie。下載地址 https://plugins.jquery.com/cookie/
    
    jquery.cookie.js基於jquery;先引入jquery,再引入:jquery.cookie.js;

<script src="{% static 'jquery.js' %}"></script>
<script src="{% static 'jquery.cookie.js' %}"></script>

$.ajax({
    
    url:'/test/',
    type:'post',
    headers:{"X-CSRFToken":$.cookie('csrftoken')}, #從Cookie取csrftoken,並設置到請求頭headers中

    #ajax裏面的headers參數,自定製請求頭,能夠將csrf_token加在這裏,咱們發contenttype類型數據的時候,csrf_token就能夠這樣加
 
})


注意:

  1.若是使用從cookie中取csrftoken的方式,須要確保cookie存在csrftoken值。

  2.若是你的視圖渲染的HTML文件中沒有包含 {% csrf_token %},Django可能不會設置CSRFtoken的cookie。-->不是全部請求都有csrftoken這個cookie鍵值對

  3.這個時候須要使用ensure_csrf_cookie()裝飾器強制設置Cookie。
    

django.views.decorators.csrf import ensure_csrf_cookie

@ensure_csrf_cookie  #強制給請求對應的響應添加csrftoken這個cookie鍵值對
def login(request):
    pass

3-3 CSRF Token相關裝飾器

from django.views.decorators.csrf import csrf_exempt,csrf_protect
    
  csrf_protect,爲當前函數強制設置防跨站請求僞造功能,即使settings中沒有設置csrfToken全局中間件。
  csrf_exempt,取消當前函數防跨站請求僞造功能,即使settings中設置了全局中間件。

示例1:   
#views.py
from django.views.decorators.csrf import csrf_exempt, csrf_protect
# @csrf_exempt
@csrf_protect
def login(request):
    if request.method == 'GET':
        return render(request,'login.html')
    else:
        username = request.POST.get('username')
        password = request.POST.get('password')
        if username == 'zhangsan' and password == '1234':

            return HttpResponse('OK')
        else:
            return redirect('login')
        
 #login.html
<form action="/login/" method="post">
  用戶名: <input type="text" name="username">
  密碼: <input type="password" name="password">
  <input type="submit">
</form>

#settings.py
    MIDDLEWARE = [
         'django.middleware.csrf.CsrfViewMiddleware',   
    ]
    
【1】settings中設置了全局中間件,在login.html中不設置{% csrf_token %},當post提交數據時,Forbidden (403)
    若是在FBV的函數上使用csrf_exempt裝飾器,能夠成功提交數據。
    
【2】settings中沒有設置全局中間件,當post提交數據時能夠成功提交。若是在FBV的函數上使用csrf_exempt裝飾器,Forbidden (403)。



示例2:注意csrf-token裝飾器的特殊性,在CBV模式下它只能加在dispatch上面。
     添加裝飾器的格式必須爲@method_decorator(),括號裏面爲裝飾器的函數名
    
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator


#@method_decorator(csrf_exempt, name='dispatch')
class HomeView(View):
    
    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        return super(HomeView, self).dispatch(request, *args, **kwargs)

    def get(self, request):
        return render(request, "home.html")

    def post(self, request):
        print("Home Viw POST method...")
        return redirect("/index/")
相關文章
相關標籤/搜索