Django之CSRF、token驗證、csrf裝飾器、auth模塊方法大全

[TOC]html

什麼是csrf?

CSRF即跨站請求攻擊。簡單的說,是攻擊者經過一些技術手段欺騙用戶的瀏覽器去訪問一個本身之前認證過的站點並運行一些操做(如發郵件,發消息,甚至財產操做(如轉帳和購買商品))。由於瀏覽器以前認證過,因此被訪問的站點會絕點是這是真正的用戶操做而去運行。python

這就利用了web中用戶身份認證驗證的一個漏洞:簡單的身份驗證僅僅能保證請求發自某個用戶的瀏覽器,卻不能保證請求自己是用戶自願發出的。

​ 其實能夠這麼理解CSRF攻擊:攻擊者盜用了你的身份,以你的名義發送惡意請求。CSRF可以作的事情包含:以你的名義發送郵件;發消息;盜取你的帳號;甚至於購買商品、虛擬貨幣轉帳......形成的問題包含我的隱私泄露以及財產安全。web

**大白話總結:**本身準備一個擁有默認值(你的銀行卡號)的input框,隱藏起來。用戶輸入轉帳的input框,沒有name屬性。用戶發送轉帳請求的時候,後端拿到的是你已經準備好的銀行卡號,而不是用戶輸入的。ajax

跨站請求僞造csrf
	釣魚網站
		本質搭建一個跟正常網站如出一轍的頁面
		用戶在該頁面上完成轉帳功能
		
		轉帳的請求確實是朝着正常網站的服務端提交
		惟一不一樣的在於收款帳戶人不一樣
		
		給用戶書寫form表單 對方帳戶的input沒有name屬性
		你本身悄悄提早寫好了一個具備默認的而且是隱藏的具備name屬性的input
	模擬釣魚網站

csrf原理

從上圖可以看出,要完畢一次CSRF攻擊,受害者必須依次完畢兩個步驟:django

​ 登陸受信任站點A,並在本地生成Cookie。後端

​ 在不登出A的狀況下,訪問危急站點B。瀏覽器

如何預防CSRF?

一、提交驗證碼

​ 在表單中添加一個隨機的數字或字母驗證碼。經過強制用戶和應用進行交互。來有效地遏制CSRF攻擊。安全

二、Referer Check

​ 檢查假設是非正常頁面過來的請求,則極有多是CSRF攻擊。服務器

三、token驗證

(1)在 HTTP 請求中以參數的形式添加一個隨機產生的 token,並在服務器端創建一個攔截器來驗證這個 token,假設請求中沒有 token 或者 token 內容不對,則以爲多是 CSRF 攻擊而拒絕該請求。cookie

(2)token必須足夠隨機

(3)敏感的操做應該使用POST,而不是GET。好比表單提交。

四、在HTTP頭中本身定義屬性並驗證

​ 這樣的方法也是使用 token 並進行驗證。這裏並不是把 token 以參數的形式置於 HTTP 請求之中,而是把它放到 HTTP 頭中本身 定義的屬性裏。經過 XMLHttpRequest 這個類,可以一次性給所有該類請求加上 csrftoken 這個 HTTP 頭屬性。並把 token 值放入當中。這樣攻克了上種方法在請求中添加 token 的不便。同一時候,經過 XMLHttpRequest 請求的地址不會被記錄到瀏覽器的地址欄,也不用操心 token 會透過 Referer 泄露到其它站點中去。

form表單中如何經過csrf校驗?

你只須要在你的form表單內寫一個  {% csrf_token %}


<form action="" method="post">
    {% csrf_token %}
    old_password:<input type="text" name="old_password">
    new_password:<input type="text" name="new_password">
    <input type="submit">

</form>

AJAX如何經過csrf校驗?

第一種方式:本身手動獲取

$('#d1').click(function () {
        $.ajax({
            url:'',
            type:'post',
            // 第一種方式 本身手動獲取
data:{'username':'jason','csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()},
            success:function (data) {
                alert(data)
            }
        })
    })

第二種方式:利用模板語法

$('#d1').click(function () {
        $.ajax({
            url:'',
            type:'post',
           // 第二種方式 利用模板語法
            data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},
            success:function (data) {
                alert(data)
            }
        })
    })

第三種方式:通用方式 引入外部js文件 官網提供的方式

$('#d1').click(function () {
        $.ajax({
            url:'',
            type:'post',
		   <script src="{% static 'myset.js' %}"></script>
            success:function (data) {
                alert(data)
            }
        })
    })

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

CSRF相關裝飾器

1.登陸認證裝飾器

使用的時候須要導入:
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator

@csrf_exempt  # 不校驗csrf
@csrf_protect # 校驗

使用方法

1.在指定函數頭上裝

@method_decorator(csrf_protect)  # 第一種方式
def post(self,request):
	return HttpResponse('post')

2.在類名頭上指名道姓給某個方法裝

@method_decorator(csrf_protect,name='post') 
class MyHome(View): 
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request,*args,**kwargs)
    def post(self,request):
        return HttpResponse('post')
    def get(self,request):
        return HttpResponse('get')

3.類中全部方法都裝

class MyHome(View): 
    @method_decorator(csrf_protect)  # 第三種 類中全部的方法都裝
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request,*args,**kwargs)
    def post(self,request):
        return HttpResponse('post')
    def get(self,request):
        return HttpResponse('get')

2.校驗用戶是否登陸裝飾器

from django.contrib.auth.decorators import login_required

使用方式:

@login_required(login_url='/index/') 能夠傳參數,重定向到頁面。這是是局部。

@login_required(login_url='/index/')
def yyy(request):
    return HttpResponse('yyy頁面')

全局修改參數方式:修改以後,影響全局。局部也能夠修改。局部修改就用局部的

在settings.py中添加:LOGIN_URL = '/login/'

Django用戶相關自帶功能模塊 auth

auth方法大全

from django.contrib import auth

1.建立用戶
    User.objects.create()  				 # 建立普通用戶,密碼是明文。不推薦
    User.objects.createuser()  			 # 建立普通用戶,基本都用它 
    User.objects.createsuperuser()  	 # 建立超級用戶,郵箱要給數據
    
2.校驗用戶名和密碼是否正確  
    auth.authenticate(username=username,password=password)  # 用戶名和密碼兩個一個都不能少
							# 該方法返回值:當用戶名和密碼正確的時候:返回的用戶對象 
        											 #不正確返回None
3.保存登陸狀態
	auth.login(request,user_obj)  # 這一句執行以後 request.user就能獲取當前登陸的用戶對象
    
4.如何判斷當前用戶是否登陸 以及如何獲取當前登陸用戶對象
	request.user.is_authenticated()  # 判斷是否登陸  BOOL值
    request.user  # 登陸用戶對象
    
5.校驗用戶是否登陸
    from django.contrib.auth.decorators import login_required
    # 局部配置
    @login_required(login_url='/login/')    # 沒有登陸跳轉的頁面
    def xxx(request):
        return HttpResponse('xxx頁面')	  # 登陸以後的
			
    # 全局配置
    配置文件中寫如下代碼
    LOGIN_URL = '/login/'
    @login_required
    def xxx(request):
    	return HttpResponse('xxx頁面')
		# 若是兩個都設置了 那麼優先執行局部配置
		
6.修改密碼
    request.user.check_password(old_password)  # 校驗原密碼是否正確
    request.user.set_password(new_password)
    request.user.save()                        # 必定要保存 
		
7.註銷功能
	auth.logout(request)  	# 刪除了對應的session值

如何擴展auth_user表?

# 1 利用一對一表關係()
	
	
# 2 利用類的繼承
    # 1 類的繼承
    from django.contrib.auth.models import User,AbstractUser
    # Create your models here.
    class Userinfo(AbstractUser):
    phone = models.BigIntegerField()
    avatar = models.FileField()
    # 擴展的字段 儘可能不要與原先表中的字段衝突

    # 2 配置文件
    AUTH_USER_MODEL = '應用名.表名'
    """
    django就會將userinfo表來替換auth_user表
    而且以前auth模塊全部的功能不變 參照的也是userinfo表
    """

相關文章
相關標籤/搜索