CSRF(Cross-site request forgery)跨站請求僞造,也被稱爲「One Click Attack」或者Session Riding,一般縮寫爲CSRF或者XSRF,是一種對網站的惡意利用。儘管聽起來像跨站腳本(XSS),但它與XSS很是不一樣,XSS利用站點內的信任用戶,而CSRF則經過假裝成受信任用戶的請求來利用受信任的網站。與XSS攻擊相比,CSRF攻擊每每不大流行(所以對其進行防範的資源也至關稀少)和難以防範,因此被認爲比XSS更具危險性。html
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同樣則本次請求合法。服務器
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', ]
#爲每一個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>
經過獲取隱藏的input標籤中的csrfmiddlewaretoken值,放置在data中發送。 data:{ csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val(), #form表單裏必須寫{% csrf_token %}#} },
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>
注意:須要引入一個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
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/")