1. 程式人生 > 實用技巧 >Django框架之十 中介軟體 csrf跨站請求偽造

Django框架之十 中介軟體 csrf跨站請求偽造

中介軟體

一、什麼是中介軟體

求的時候需要先經過中介軟體才能到達django後端(urls,views,templates,models)

響應的時候也需要經過中介軟體才能到達web服務閘道器介面

django預設的七個中介軟體

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',
    ]

二、django中介軟體作用(********)  

1.網站全域性的身份校驗,訪問頻率限制,許可權校驗。。。只要是涉及到全域性的校驗你都可以在中介軟體完成

2.django的中介軟體是所有web框架中做的最好的

三、中介軟體執行順序

-process_request()方法,從上往下執行
        1.如果返回 HttpResponse物件,那麼會直接返回,不再往下執行而是跳到同級別的process_response方法,直接往回走
        2.請求來的時候,會經過每個中介軟體裡面的process_request方法(從上往下)
-process_response,從下往上執行
        1.必須要將response形參返回,這個形參指代的就是要返回給前端的資料
2.響應走的時候,會依次經過每一箇中間件裡面的process_response方法(從下往上)

  

四、自定義中介軟體

1.導包

from django.utils.deprecation import MiddlewareMixin

2.定義類,繼承MiddlewareMixin  

在app01應用中建立一個資料夾mymiddleware,再建立一個mdd.py檔案

class MyMdd(MiddlewareMixin):
    def process_request(self,request):
        print('我是第一個中介軟體裡面的process_request方法')

    def process_response(self,request,response):
        print('我是第一個中介軟體裡面的process_response方法')
        return responseclass
MyMdd1(MiddlewareMixin): def process_request(self,request): print('我是第二個中介軟體裡面的process_request方法') def process_response(self,request,response): print('我是第二個中介軟體裡面的process_response方法') return response

3.定義檢視函式  

def index(request):
    print("view函式...")
    return HttpResponse("OK")

4.在settings中MIDDLEWARE註冊自定義中介軟體  

MIDDLEWARE =[
     'mymiddleware.mdd.MyMdd',
     'mymiddleware.mdd.MyMdd1',
     'mymiddleware.mdd.MyMdd2',

]

5.設定路由  

urlpatterns = [
    url(r'^index/',view.index)

]

結果

我是第一個中介軟體裡面的process_request方法
我是第二個中介軟體裡面的process_request方法
view函式...
我是第二個中介軟體裡面的process_response方法
我是第一個中介軟體裡面的process_response方法

五、中介軟體五個可以自定義的方法

需要掌握的方法:

1.process_request()方法 請求來的時候會走該方法

1.請求來的時候 會經過每個中介軟體裡面的process_request方法(從上往下)
2.如果方法裡面直接返回了HttpResponse物件 那麼會直接返回 不再往下執行
    基於該特點就可以做訪問頻率限制,身份校驗,許可權校驗

2.process_response()方法 響應回去的時候會走該方法

1.必須將response形參返回 因為這個形參指代的就是要返回給前端的資料
2.響應走的時候 會依次經過每一箇中間件裡面的process_response方法(從下往上)

 需要了解的方法: 

  

3.process_view()

在路由匹配成功執行檢視函式之前 觸發

4.process_exception()

當你的檢視函式報錯時,就會自動執行

5.process_template_response()

當你返回的HttpResponse物件中必須包含render屬性才會觸發
def index(request):
    print('我是index檢視函式')
    def render():
        return HttpResponse('什麼鬼玩意')
    obj = HttpResponse('index')
    obj.render = render
    return obj

總結:

你在書寫中介軟體的時候,只要形參中有response,你就應該順手將其返回,這個response就是要給前端的資訊。

這五種方法有哪些特點:
1.都需要繼承MiddlewareMixin
2.在註冊中介軟體的時候,在settings中寫的路徑不能錯

CSRF——跨站請求偽造

1.什麼是CSRF攻擊

攻擊者盜用了你的身份,以你的名義傳送惡意請求,對伺服器來說這個請求是完全合法的。

比如釣魚網站

2.CSRF攻擊原理

要完成一次CSRF攻擊,受害者必須依次完成兩個步驟:

  1.登入受信任網站A,並在本地生成Cookie。

  2.在不登出A的情況下,訪問危險網站B。

釣魚網站例子

通過製作一個跟正兒八經的網站一模一樣的頁面,騙取使用者輸入資訊 轉賬交易從而做手腳
轉賬交易的請求確確實實是發給了中國銀行,賬戶的錢也是確確實實少了
唯一不一樣的地方在於收款人賬戶不對
內部原理
    在讓使用者輸入對方賬戶的那個input上面做手腳
    給這個input不設定name屬性,在內部隱藏一個實現寫好的name和value屬性的input框
    這個value的值 就是釣魚網站受益人賬號

如何區分釣魚網站和正經網站?在正經網站返回頁面的時候,在form表單中偷偷塞一個特殊的字串,後端記下該頁面對應的字串的值,等使用者發post請求來的時候,我先去校驗特殊的字串是否匹配

如何去寫這個特殊的字串呢?模版語法有一個固定的寫法{% csrf_token %},必須寫在form表單內

3.CSRF攻擊防範

防止釣魚網站的思路
    網站會給使用者訪問的form表單頁面 偷偷塞一個隨機字串
    請求到來的時候 會先比對隨機字串是否一致  如果不一致  直接拒絕(403)

該隨機字串有以下特點
  1.同一個瀏覽器每一次訪問都不一樣
  2.不同瀏覽器絕對不會重複

4.CSRF在Django中的應用

1.在form表單中使用

<form action="" method="post">
    {% csrf_token %}
    <p>username:<input type="text" name="username"></p>
    <p>password:<input type="text" name="password"></p>
    <input type="submit">
</form>

2.在ajax中使用,如何避免csrf校驗

  • 有兩種方法,通過修改ajax的data

  方法一:先在form表單頁面上寫{% csrf_token%},利用標籤查詢,獲取到該input鍵值訊息

data{'username':'jason','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()}

  方法二:直接書寫'{{csrf_token}}'

data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'}
  • 還可以將獲取隨機鍵值對的方法,寫到一個js檔案中,然後匯入這個檔案即可

  新建一個js檔案,存放以下程式碼

function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
             // Does this cookie string begin with the name we want?
             if (cookie.substring(0, name.length + 1) === (name + '=')) {
                 cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                 break;
             }
        }
     }
     return cookieValue;
}
var csrftoken = getCookie('csrftoken');


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);
         }
     }
 });

5.CSRF禁用

1.CSRF全域性禁用

註釋掉settings中MIDDLEWARE的中介軟體 'django.middleware.csrf.CsrfViewMiddleware',

2.CSRF區域性禁用

  • 在FBV中,直接載入FBV就行了(在頁面不加csrf_token情況下)
from django.views.decorators.csrf import csrf_exempt,csrf_protect
#(前提是全域性使用,沒有註釋csrf) 讓這個不用校驗,可以區域性使用
#當你網站全域性需要校驗csrf的時候,有幾個不需要校驗該如何處理 @csrf_exempt def login(request): return HttpResponse('login') #(前提是全域性禁用,註釋csrf,不會進行校驗) 設定就會進行校驗,區域性禁用
#當你網站全域性不校驗csrf的時候,有幾個需要校驗又該如何處理 @csrf_protect def lll(request): return HttpResponse('lll')
  • 在CBV中,只能在dispatch方法或者類上面
from django.views import View
from django.views.decorators.csrf import csrf_exempt,csrf_protect
from django.utils.decorators import method_decorator
# 這兩個裝飾器在給CBV裝飾的時候 有一定的區別
如果是csrf_protect 那麼有三種方式
    # 第一種方式
    # @method_decorator(csrf_protect,name='post')  # 有效的
    class MyView(View):
        # 第三種方式
        # @method_decorator(csrf_protect)
        def dispatch(self, request, *args, **kwargs):
            res = super().dispatch(request, *args, **kwargs)
            return res

        def get(self,request):
            return HttpResponse('get')
        # 第二種方式
        # @method_decorator(csrf_protect)  # 有效的
        def post(self,request):
            return HttpResponse('post')
如果是csrf_exempt 只有兩種(只能給dispatch裝) 特例 @method_decorator(csrf_exempt,name='dispatch') # 第二種可以不校驗的方式 class MyView(View): # @method_decorator(csrf_exempt) # 第一種可以不校驗的方式 def dispatch(self, request, *args, **kwargs): res = super().dispatch(request, *args, **kwargs) return res def get(self,request): return HttpResponse('get') def post(self,request): return HttpResponse('post')