Django 2.0 學習(22):Django CSRF

Django CSRF

CSRF攻擊過程

攻擊說明:
1.用戶C打開瀏覽器,訪問受信任網站A,輸入用戶名和密碼請求登錄網站A;
2.在用戶信息經過驗證後,網站A產生Cookie信息並返回給瀏覽器,此時用戶登錄網站A成功,能夠正常發送請求到網站A;
3.用戶未退出網站A以前,在同一瀏覽器中,打開一個TAB頁訪問網站B;
4.網站B收到用戶請求後,返回一些攻擊性代碼,併發出一個請求,要求訪問第三方站點A;
5.瀏覽器在接收到這些攻擊性代碼後,根據網站B的請求,在用戶不知情的狀況下攜帶Cookie信息,向網站A發出請求。網站A並不知道該請求實際上是由B發起的,因此會根據用戶C的Cookie信息以C的權限處理該請求,致使來自網站B的惡意代碼被執行。前端

CSRF的攻擊之因此會成功是由於服務器端身份驗證機制能夠經過Cookie保證一個請求是來自於某個用戶的瀏覽器,>單沒法保證該請求是用戶容許的。所以,預防CSRF攻擊簡單可行的方法就是在客戶端網頁上添加隨機數,在服務器>端進行隨機數驗證,以確保該請求是用戶容許的。Django也是經過這個方法來預防CSRF攻擊的。ajax

Django防護CSRF攻擊

原理
在客戶端頁面上天機csrftoken,服務器端進行驗證。服務器端驗證的工做經過"django.middleware.csrf.CsrfViewMiddleware"這個中間件來完成。在Django中防護csrf攻擊的方式有兩種:django

  • 在表單中附加csrftoken;
  • 經過request請求中添加x-csrftoken請求頭;

注意:Django默認對全部的POST請求都進行csrftoken驗證,若驗證失敗則返回403錯誤。Django中設置防跨站請求僞造功能分爲全局和局部。
全局:中間件 django.middleware.csrf.CsrfViewMiddleware
局部:from django.views.decorators.csrf import csrf_protect, csrf_exempt後端

  • @csrf_protect,爲當前函數強制設置防跨站請求僞造功能,即使settings中沒有設置全局中間件;
  • @csrf_exempt,取消當前函數防跨站請求僞造功能,即使settings中設置了全局中間件;

當用post提交數據的時候,django會去檢查是否有一個csrf的隨機字符串,若是沒有就會報錯,錯誤以下:

在Django內部支持生成這個隨機字符串。瀏覽器

經過form提交
在form表單裏面須要添加{% csrf_token %},這樣當查看頁面源碼的時候,能夠看到form中有一個input是隱藏的:
服務器

原理總結:
當用戶訪問login頁面的時候,會生成已給csrf的隨機字符串,而且cookie中野村放了這個隨機字符串,當用戶再次提交數據的時候會帶着這個隨機字符串提交,若是沒有這個隨機字符串則沒法提交成功。cookie中存放的csrftoken以下圖所示:
cookie

經過ajax提交
由於cookie中一樣存在csrftoken,因此能夠在JavaScript中經過$.cookie("csrftoken")獲取。若是經過ajax進行提交數據,這裏提交的csrftoken是經過請求頭中存放,須要提交一個字典型的數據,即這時候須要一個key。在views中的login函數中:from django.conf import settings,而後打印print(settings.CSRF_HEADER_NAME),這裏須要注意一個問題,這裏導入的settings並非咱們在項目下看到的settings.py文件,這裏是一個全局的settings配置,而當咱們在項目目錄下的settings.py中配置的時候,咱們添加的配置則會覆蓋全局settings中的配置。print(settings.CSRF_HEADER_NAME)打印的內容爲:HTTP_X_CSRFTOKEN,這裏的HTTP_X_CSRFTOEKN是Django在X_CSRF的前面添加了HTTP_,因此實際傳遞的就是X_CSRFTOKEN,而在前端頁面的ajax傳遞的時候因爲不能使用下劃線,因此傳遞的是X_CSRFTOKEN。下面是在前端ajax中寫的具體內容:併發

$("#btn1").click(function () {
        $.ajax({
            url:"/login/",
            type:"POST",
            data:{"usr":"root","pwd":"123"},
            headers:{ "X-CSRFtoken":$.cookie("csrftoken")},
            success:function (arg) {

            };
        });
    });

可是若是頁面中有多個ajax請求的話,就在每一個ajax中添加headers信息,因此能夠經過下面方式在全部的ajax中都添加:函數

$.ajaxSetup({
            beforeSend:function (xhr,settings) {
                xhr.setRequestHeader("X-CSRFtoken",$.cookie("csrftoken"))
            }
        });

這樣就會在提交ajax以前執行這個方法,從而在全部的ajax裏都加上這個csrftoken,這裏的xhr是XMLHttpRequest的簡寫,ajax調用的就是這個方法。若是想要實如今當get方式的時候不須要提交csrftoken,當post的時候須要,實現這種效果的代碼以下:post

function csrfSafeMethod(method) {
            // these HTTP methods do not require CSRF protection
            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
        }
        $.ajaxSetup({
            beforeSend: function(xhr, settings) {
                if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                    xhr.setRequestHeader("X-CSRFToken", csrftoken);
                };
            };
        });

這樣就實現了當GET|HEAD|OPTIONS|TRACE這些方式請求的時候不須要提交csrftoken。

總結: 一、csrf在ajax提交的時候經過請求頭傳遞給後臺的; 二、csrf在前端的key爲:X-CSRFToken,到後端的時候Django會自動添加HTTP_,而且最後爲HTTP_X_CSRFTOKEN; 三、csrf在form中提交的時候須要在前端form中添加{% csrftoken %};

相關文章
相關標籤/搜索