跨站請求偽造(CSRF)與跨站請求腳本正好相反。跨站請求腳本的問題在於,客戶端信任服務器端發送的數據。跨站請求偽造的問題在於,服務器信任來自客戶端的數據。
無CSRF時存在的隱患
跨站請求偽造是指攻擊者通過HTTP請求江數據傳送到服務器,從而盜取回話的cookie。盜取回話cookie之后,攻擊者不僅可以獲取用戶的信息,
還可以修改該cookie關聯的賬戶信息。
2. CSRF在Django中
django為用戶實現防止跨站請求偽造的功能,通過中間件 django.middleware.csrf.CsrfViewMiddleware 來完成。
而對於django中設置防跨站請求偽造功能有分為全局和局部。
全局:
中間件 django.middleware.csrf.CsrfViewMiddleware
局部:
@csrf_protect,為當前函數強制設置防跨站請求偽造功能,即便settings中沒有設置全局中間件。
@csrf_exempt,取消當前函數防跨站請求偽造功能,即便settings中設置了全局中間件。
注意:from django.views.decorators.csrf import csrf_exempt,csrf_protect

3. 處理csrf四種方法
django 第一次響應來自某個客戶端的請求時(get方式),會在服務器端隨機生成一個 token,然后把這個 token 寫在用戶請求的 cookie 里,同時也會給客戶端頁面發送一個隨機的 token (form表單中以{% csrf_token %}方式獲取)用以認證。之后客戶端每次以 POST 方式向服務端提交請求時,都會帶上這個 token,這樣就能避免被 CSRF 攻擊。
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 的值
4. 基本應用
直接在form表單中添加:就能應用。
{% csrf_token %} -----> 轉換成一個hidden屬性的input標簽
{{ csrf_token }} -----> 直接獲取csrf的隨機字符串
注意:本地的cookies中也會添加隨機字符串 ---> 注意key名
5 .全站禁用:
- 整個框架不使用csrf安全機制,直接在settings.py文件中注銷,整個網站都不再應用。
# 'django.middleware.csrf.CsrfViewMiddleware',
6 .局部禁用:全局使用,但是某些函數不需要應用
- 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')
7. 局部使用:全局不使用,但是某些函數需要應用
# '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')
8 .特殊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
9. Ajax提交數據時候,攜帶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>
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);
}
})
}
10 . AJAX 中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>
11. django csrf注意點
注意一定注意:ajax POST提交的時候,csrf-token 隨機字符串 直接放在data數據中的方式為:data:{csrfmiddlewaretoken:"{{ csrf_token }}"}
若是導入自己寫的JS文件,那上述方法就不能獲取到Django后台發送的隨機字符串,而是需要利用上面介紹的兩種方式獲取(頁面寫上{% csrf_token %},通過隱藏的input標簽取value值寫在POST
提交的data數據中;或是從cookie中獲取,寫在頭文件中。)
使用django框架時:
每次初始化一個項目時都要看看 django.middleware.csrf.CsrfViewMiddleware 這個中間件
每次在模板里寫 form 時都需要加一個 {% csrf_token %} tag
每次發 ajax POST 請求,都需要加一個 X_CSRFTOKEN 的 head